Value Object: a better implementation

This post is about a better implementation of Value Object.

Value Object: a better implementation

I believe you know what a value object is. Here’s a thorough article about it and what differentiates it from an Entity if you need a refresher: Entity vs Value Object: the ultimate list of differences.

In short, value objects are the building blocks of your domain model. Ideally, you want any concept, however small it is, to be represented by a value object. Got a user with an email? Wrap this email in a separate value object class. Are there several fields that represent an address? Even better, extracting them into a value object would reduce the number of properties the user entity needs to work with.

For many years, I’ve been using an implementation of it which I presented in the DDD in practice course. Here it is:

What it does is it handles the repeating parts of the equality members and provides extension points for deriving classes to do the actual comparison and hash code calculation.

Here’s what an Address value object deriving from that base class could look like:

As you can see, the base value object class does a pretty good job hiding most of the boilerplate code related to comparison operations. All you need to do is declare two methods. The first one is EqualsCore whose parameter other is already strongly typed, so you don’t need to deal with conversion or anything like that. And the second one is GetHashCodeCore. It doesn’t bring a lot of additional value as you could just override the standard GetHashCode, but the benefit of having this additional abstract method is that it helps you to not forget about defining it in the deriving classes.

It’s possible to move even more responsibilities to the base ValueObject class. For example, I saw implementations where the base class used .NET reflection to get the list of all fields and properties in the deriving class and perform the comparison automatically. While it might seem like a good idea as it allows you to reduce the amount of code in Address even further, I would recommend against it.

The reason why is because such approach fails in two scenarios:

  • It doesn’t work if the value object contains a collection. Collections need special treatment: taking each element and comparing them one by one instead of simply calling Equals() on the collection instance.
  • It doesn’t work if you need to exclude one of the fields from the comparison. It might be the case that not all properties in a value object created equal. There could be some Comment field that doesn’t need to be compared when evaluating equality. At the same time, there’s no way to inform the value object about this. All fields in the derived class will be taken into account and compared against each other.

So, the actual comparison logic in value objects should be implemented consciously, there’s no way you can delegate it to an automatic tool. Hence you need to do a little bit of work in the derived classes by declaring EqualsCore and GetHashCodeCore.

However, it is still possible to reduce the amount of work needed. Instead of doing the actual comparison and hash code calculation in the derived classes, you can ask them to enumerate the members that participate in the comparison and do the rest of the work in the base class.

This idea was proposed by a reader of this blog, Steven Roberts. Here’s how the new ValueObject class looks:

And this is the updated Address:

As you can see, there’s a lot more going on in the new version of the base class. It doesn’t require you to implement EqualsCore anymore. Instead, you only need to provide the list of components that comprise the class. The comparison is done by using SequenceEqual() on the two sets of such components. GetHashCode is also taken care of: it now takes each component and uses it to build up the resulting hash code.

As for Address, all it needs to do is this:

This approach reduces the amount of repeating code in the derived classes and at the same time doesn’t exhibit the drawbacks of the implementation with the fully automatic comparison. You can still choose which fields you want to take into consideration. And if the value object contains collections, it will work too. All you need to do is enumerate all collection elements alongside with other properties.

This is what you would need to do should you decide to add a list of tenants to the Address value object:

And here’s what to do if you need to override the default Equals() behavior, for example, implement case-insensitive comparison for a string and specify the precision for a float/double/decimal type:

Note that GetEqualityComponents() transforms Currency into the upper case and rounds Amount up to two decimal points, so that now it doesn’t matter if you use


They would be deemed equal from the domain’s point of view.


I like this implementation a lot as it’s simpler than the one I used previously. All kudos to Steve Roberts.

Related articles



  • Stanko Culaja

    Great solution!

    Do you plan to move this implementation to CSharpFunctionalExtensions repo and nuget?

    • Vladimir Khorikov

      I would like to, but not sure how to do that yet. That would be a breaking change for everyone who upgrades from the previous version.

      • Stanko Culaja

        Yes, it is a problem.

        Maybe to put it in a different namespace and mark previous implementation as obsolete. Those are the breaking changes but it is not hard to align the broken classes with new implementation (especially if you have unit tests).

        • Vladimir Khorikov

          Either that or force folks to modify their Value Objects by introducing the breaking change with a thorough description of how to do that. Will need to test the most convenient option.

  • Pavel Shilyagov

    Or you can just use F# 🙂
    It’s a shame that we still need to implement structural equality manually in 2017.

    • Vladimir Khorikov

      Records in C# could help alleviate this problem.

  • Amir Shitrit

    Should Tenants list be sorted first in order for the SequenceEquals to work well?

    • Vladimir Khorikov

      That would depend on the requirements. If the position of the tenants is not important, then yes, we would need to sort them first. If it is, then we’d need to keep the collection as is to make sure two addresses are equal only if their tenants positioned the same way.

  • Stefan Bertels

    You should have a look at LanguageExt.Core by Paul Louth (on github/nuget). He solved thus problem in a type-safe way (Record). It’s an awesome library!

    • Vladimir Khorikov

      Create library, but I don’t like relying on .NET reflection for this particular use case.

      • Stefan Bertels

        Have a deeper look.
        Does not use reflection AFAIK.
        Generates code, of course. AFAIK this is the only type safe solution removing boiler plate (until record types will arrive in C# 9.0?).

  • ardalis

    I assume you’re familiar with Jimmy Bogard’s ValueObject type here:

    This is what Julie Lerman and I used in the Domain-Driven Design Fundamentals course ( It has the advantage of also implementing IEquatable, and it doesn’t require any special code in the child classes. It does, however, rely on reflection, so there are performance tradeoffs. For most business software applications, though, this is unlikely to pose a (legitimate) concern.

    • Vladimir Khorikov

      I’m familiar with Jimmy Bogard’s implementation. It has the drawbacks I described in the article when I referred to implementations relying on .NET reflection: you can’t omit particular members from the comparison and you can’t deal with collections. I agree that it’s enough for most simple cases, though.

      It has the advantage of also implementing IEquatable

      There’s no need in implementing IEquatable, this interface was introduced specifically to avoid boxing/unboxing of .NET value types (structs) when dealing with comparison. As long as you implement ValueObject as class, you can safely omit implementing IEquatable.

      • Joseph N. Musser II

        It saves a cast though, which could add up if the BCL is using EqualityComparer<SomeValueObject>.Default against a lot of items.

        • Vladimir Khorikov

          True, but I don’t think an additional cast on a reference type is something that would be noticeable in a typical enterprise application. Adherence to YAGNI is more important in this context.

          • Joseph N. Musser II

            I don’t see it as a YANGI thing because it’s an ubiquitous thing that has no cost. If you’re going to simplify in the name of YAGNI to the point where we’re getting rid of ubiquitous BCL vocabulary, then it would make more sense to make GetHashCode virtual and return 0. Unlike IEquatable, implementing GetHashCode does actually exact a cost on every programmer implementing a derived class. Perf in hashtables will go down unless they do override, but behavior will be correct.

          • Joseph N. Musser II

            On top of that, it’s also probably a good idea to add a obj.GetType() ==
            check in a public sealed
            Equals(T) method which then delegates to a protected abstract EqualsCore(T) method. It keeps the symmetric property of equality when a more derived class is provided.

            Once you add that method, all you need is to add : IEquatable<T>.

          • Vladimir Khorikov

            Additional code always entails cost, there’s rarely such thing as cost-free code. You might argue that this cost is not big and I would agree. But the benefit of having such code is also small, so all things being equal, I prefer adherence to YAGNI.

            Regarding GetHashCode, I haven’t tested it, but I think the performance impact of such an overriding would be more than that of an additional cast for reference types. I might be wrong here, though.

            Regarding obj.GetType() == this.GetType(), this check is simulated by this code:

            var valueObject = obj as ValueObject;
            if (ReferenceEquals(valueObject, null))
            return false;

            No need to do the additional type check.

          • Joseph N. Musser II

            Actually, here’s a demo showing that the additional type check is necessary:

            var address = new Address(“”, “”, “”);
            var derived = new DerivedAddress(“A”, “”, “”, “”);

            address.Equals(derived) // True
            derived.Equals(address) // False

            public class DerivedAddress : Address
            public string Country { get; }

            public DerivedAddress(string country, string street, string city, string zipCode)
            : base(street, city, zipCode)
            Country = country;

            protected override bool EqualsCore(Address other)
            return other is DerivedAddress derived
            && base.EqualsCore(derived)
            && Country == derived.Country;

            Address.Equals(object) should be able to tell that a derived class was handed in and return false, but it’s not.

          • Vladimir Khorikov

            Good point. I’ll add this check.

      • The Other Mike

        I have been using the version of the ValueObject class that uses GetEqualityComponents for several months and it has been a real boon, but I made it implement IEquatable. There have been cases where I was using a generic key that needed value equality. That generic key could be a structure like int32, a class with value equality like String, or a ValueObject, but should not be a class with reference equality. As you probably know, the is no way to spec an OR on generic type constraints, only AND. ValueObject implementing IEquatable came to the rescue here. I can put IEquatable as my type constraint and catch exactly these cases since Microsoft’s states that the only purpose for using overriding Equals and implementing IEquatable is “This interface is implemented by types whose values can be equated”. Worked out perfect!

        Thanks for publishing this handy ValueObject concept. There have been projects that I have deleted tons of (sometimes buggy) Equals overloads and = operators and replaced with your elegant ValueObject and GetEqualityComponent. I highly recommend you add IEquatable to your official recommendation as there is very little downside.

        Also if you want to publish a VB.NET version:

        ‘modified from
        ‘ and

        Public MustInherit Class ValueObject
        Implements IEquatable(Of ValueObject)

        Protected MustOverride Function GetEqualityComponents() As IEnumerable(Of Object)

        Public Overrides Function Equals(ByVal other As Object) As Boolean
        If other Is Nothing Then Return False
        If Me.GetType other.GetType Then Return False ‘Throw New ArgumentException($”Invalid comparison of Value Objects of different types: {Me.GetType} and {obj.GetType}”)
        Return Equals(DirectCast(other, ValueObject))
        End Function

        Public Overloads Function Equals(other As ValueObject) As Boolean Implements IEquatable(Of ValueObject).Equals
        Return GetEqualityComponents.SequenceEqual(other.GetEqualityComponents)
        End Function

        Public Overrides Function GetHashCode() As Integer
        Dim hash As Long = 17
        For Each obj In GetEqualityComponents()
        hash = hash * 23 + obj.GetHashCode()
        Return hash.GetHashCode
        End Function

        Public Shared Operator =(ByVal a As ValueObject, ByVal b As ValueObject) As Boolean
        If a Is Nothing AndAlso b Is Nothing Then Return True
        If a Is Nothing OrElse b Is Nothing Then Return False
        Return a.Equals(b)
        End Operator

        Public Shared Operator (ByVal a As ValueObject, ByVal b As ValueObject) As Boolean
        Return Not (a = b)
        End Operator

        End Class

    • Harry McIntyre

      I don’t know if you’ve seen my lib, ValueOf? It takes advantages of ValueTuple to allow one-liner definition of Value Objects, and there’s no reflection.

      public class Address: ValueOf<(string street, string city, string zipCode, List tenants), Address>{}

      var address = Address.From(("Foo", "Bar", "Baz", tenants);

      You do have to use `address.Value` to get to the properties though… You could add additional getters properties on the Type I guess.

      All these Value Object types seem to be numbered though… C# 8 is going to give us Record types:

      public class Address(string street, string city, string zipCode, List tenants)

    • Thomas Hansen

      Even though it’s interesting per se, it’s using reflection, which makes things slooooooow …!!

  • Husain Abdali

    Let me first thank you for your great blog and Pluralsight courses. Well, this implementation is very much similar to a beautiful implementation I have seen in CodePlex.

    The base class

    One of its derived classes

    I would really love to hear any input you might have about it.

    • Vladimir Khorikov

      It’s indeed very similar. The only thing I would improve the version from CodePlex is I would move `operator ==` and `operator !=` to the base class. No need to redefine them in the deriving classes.

  • Harry McIntyre

    Using a standard collection type as a Value Object property is perhaps an example of Primitive Obsession in itself 🙂 We need an EquitableImmutableList

  • Mickaël Leclerc

    Hi Vladimir,
    Let’s say we have a position ValueObject containing two float fields X and Y. I would like to use a custom IEqualityComparer to manage floating point rounding issue. How could I implement it using this new version of ValueObject.
    Thank you.

    • Vladimir Khorikov

      Take a look at the example in the article (at the end of it), there’s Money that needs to have its Amount property rounded:

      public class Money : ValueObject
      public string Currency { get; }
      public decimal Amount { get; }

      public Money(string currency, decimal amount)
      Currency = currency;
      Amount = amount;

      protected override IEnumerable GetEqualityComponents()
      yield return Currency.ToUpper();
      yield return Math.Round(Amount, 2);

      • Mickaël Leclerc

        Damn, the answer was in your article, I didn’t read it carefully. I feel stupid now ^^

        • Vladimir Khorikov

          No worries at all. Cheers!

  • The Other Mike

    Microsoft recommends not throwing an exception from an Equals method or an equality operator. Maybe your throw “Invalid comparison of Value Objects” should instead just return false. I am not completely sure of their reasoning, whether it is the principle of least surprise, or tool chains that do not expect the exception.

    Older document, but I think it still holds true:

    • Vladimir Khorikov

      Yeah, I saw it, and I actually had this implementation initially. I think the reasoning behind this guideline is that you might want to compare an instance of a parent class with an instance of a derived one. And that is a valid use case generally. But Value Objects are a special case. If you compare 2 value objects of different types, it always means that there’s a bug in the code.

      I might be wrong here, so if you have a counter-example of when such a comparison might be useful – please share. I couldn’t come up with one, though.

  • zafer b

    I’m wondering if any interfaces other than IEquatable would be needed on the run, like IComparable, IEquatable etc? Though I’ve read the discussions below, I’m wondering if it’s needed and when.

    • Vladimir Khorikov

      I don’t think there’s a case for the base class to implement IComparable. It’s up to the concrete classes to do so.

  • Tom T.

    Thanks for the article.
    If using .net core 2.1+ we could use the HashCode Struct for generating the hash code thus omitting the magic equation that computes it.

  • Xavier L.

    Hi Valdimir,

    With the second implementation, how would handle an object like an undirected edge in a graph ?

    For instance :

    class UndirectedEdge {
    public T Source { get; }
    public T Target { get; }

    In this case, undirectedEdge1.Equals(undirectedEdge2) should return true if both sources and both targets are equal, but also if source1 equals target2 and source2 equals target1.

    Vertices are not necessarily comprable, so I cannot sort them in any way.

    Any idea ? Thanks !

    • Vladimir Khorikov

      That’s an interesting example. This class is a Value Object but I don’t see how this can be done with the current implementation of the Value Object base class, unfortunately. Seems that you’ll have to use the earlier, more flexible, version.

      Using `base.EqualsCore` should be good. This is how behavior is passed and re-used in OOP anyway, so I don’t see why not to rely on it here.

      • Xavier L.

        I agree. In the end there are solutions to handle that in the second implementation (adding a special case method that will get evaluated in the equals as well, and that will deal with stuff like this, but it’s not too elegant).
        That’s a shame, because this implementation greatly siplifies Equals overridings…
        Thanks for the quick reply 🙂

  • Mitch

    A very nice implementation. I’m learning more about DDD and have one question about your GetEqualityComponents() with nested value objects.
    Let’s say I have the following:

    public class BudgetGoal: ValueObject {
    public Owner Owner { get; private set; }
    public Currency YearlyAmt { get; private set; }
    public class Owner: ValueObject {
    public string Name { get; private set; }
    public class Currency: ValueObject {
    public IsoCurrencyCode CurrencyCode { get; private set; }
    public decimal Amount { get; private set; }

    What would I use for GetEqualityComponents() in class BudgetGoal?

    protected override IEnumerable GetEqualityComponents() {
    yield return Owner;
    yield return YearlyAmt;

    Or do I have to manually return the recursive elements? (This assumes a simple equality compare of all elements)

    protected override IEnumerable GetEqualityComponents() {
    yield return Owner.Name;
    yield return YearlyAmt.Amount;
    yield return YearlyAmt.CurrencyCode.Code;

    Or yet another way like calling into Child.GetEqualityComponents() within class BudgetGoal?

    • Vladimir Khorikov

      The first option, for sure. This is one of the main selling points of the approach with `GetEqualityComponents()` – you don’t need to worry about how the components of a value object implement their equality. Furthermore, it’s not the responsibility of BudgetGoal to define the equality of Owner and Currency, this should be done in those classes themselves.

  • Dmitry Dez

    Value types often contain many primitive BCL value types (int, float, and etc.). Would converting them all to IEnumerable cause boxing and hurt performance when say doing a lot of searches in array of value types? In this case version 1 with generic would be more preferable but why did you mark it as obsolete in your git hub. I think both versions have applicability depending on the use case.

    • Vladimir Khorikov

      That’s a good point, I should probably remove the Obsolete mark.

  • Thomas Hansen

    You’ve got a pretty interesting blog. Particularly enjoyed your ValueType (this blog) and the comparison between EF and NHibernate. the latter, is it still true btw …?

    As in: Is NH still that much better than EF …?

    • Vladimir Khorikov

      It is, yes. Maybe the situation will change with EF Core 3.0, though I doubt.

      • Thomas Hansen

        Thank you, now all we’ve got to do, is to convey the truth to all those who did the EF cool aid … 😉

  • Abhinav Galodha

    Good Article to clearly demonstrate a clean implementation of the Value Object.

    @vladimirkhorikov:disqus – What do you think if the Value Object class should be sealed or not?

    • Vladimir Khorikov

      Thank you. All classes should be sealed by default and made unsealed only when needed.