Value Objects (VO) are a core part of DDD. A Value Object is an immutable type that is distinguishable only by the state of its properties, it doesn’t have the concept of identity.
Value Objects can better represent some domain concepts compared to entities
IMHO the main advantage of using Value Objects is that they can better represent and model certain real world concepts compared to regular entities with identities.
For example if we are dealing with money our domain might not care about the fact two $5 notes are different, for our business $5 is $5. If on the other hand we are some central bank or the US Fed and want to track the flow of currency in an economy then $5 with the serial number ABC is considered different than the $5 with the serial number XYZ.
Both domains above deal with money but how its handled and compared in each one is different. Value Objects give us the extra level of granularity needed to more correctly model this difference.
Always valid after creation
Another big benefit from using Value Objects comes from the fact they are immutable, this means once we validate them on creation we never have to worry about validation again. This can simplify our code base significantly.
To keep things simple in this case we don’t have a full Value Object implementation as we don’t have logic for comparing two Value Objects together. This can be done a number of ways but a typical implementation is to use an abstract base class along with an overridden method in our derived Value Type which will return the list of properties we need to include when comparing two Value Objects.
Using Records for Value Objects in C#?
Records were introduced in C#9 and give us built in immutability and comparison checks. Can we use them to model Value Objects? In many cases yes, but beware there are some limitations when using records over classes to model Value Objects as discussed by Vladimir Khorikov.
What does your typical Value Object implementation look like? Do you mostly use Records or Classes?