There are few new features in C# 9.0 that provide more clarity in terms of how to express code that is better aligned with your thoughts.
An example of such feature is "record". Instead of declaring a type as class, you can declare it as a record and that becomes immutable - perfect for message passing. It is much closer to what you would call a "Value Object". Better yet, there is an in-built implementation of ToString() function and value comparison is automatically taken care of - you don't need to write a comparer yourself.
What goes on in the backend - well - record gets compiled as a class which implements IEquatable<T> and provides override implementation of multiple methods.
Consider this example.
If you look at the compile code, it looks like below.