Generic Value Object

I just wanted to share my attempt for implementing a generic base class for Value Objects, popularized by Eric Evans and the Domain-Driven Design community. I must say that I got heavily inspired by Jimmy Bogard’s implementation, which got me thinking about such an approach. Contrary to his implementation, I used static reflection instead of dynamic reflection in order to determine which fields to use for equality and string representation.

public abstract class ValueObject<T> : IEquatable<T>
    where T : ValueObject<T>
{
    private List<PropertyInfo> Properties { get; set; }

    protected ValueObject()
    {
        Properties = new List<PropertyInfo>();
    }

    public override Boolean Equals(Object obj)
    {
        if(ReferenceEquals(null, obj)) return false;
        if(obj.GetType() != GetType()) return false;

        return Equals(obj as T);
    }

    public Boolean Equals(T other)
    {
        if(ReferenceEquals(null, other)) return false;
        if(ReferenceEquals(this, other)) return true;

        foreach(var property in Properties)
        {
            var oneValue = property.GetValue(this, null);
            var otherValue = property.GetValue(other, null);

            if(null == oneValue || null == otherValue)  return false;
            if(false == oneValue.Equals(otherValue)) return false;
        }

        return true;
    }

    public override Int32 GetHashCode()
    {
        var hashCode = 36;
        foreach(var property in Properties)
        {
            var propertyValue = property.GetValue(this, null);
            if(null == propertyValue)
                continue;

            hashCode = hashCode ^ propertyValue.GetHashCode();
        }

        return hashCode;
    }

    public override String ToString()
    {
        var stringBuilder = new StringBuilder();
        foreach(var property in Properties)
        {
            var propertyValue = property.GetValue(this, null);
            if(null == propertyValue)
                continue;

            stringBuilder.Append(propertyValue.ToString());
        }

        return stringBuilder.ToString();
    }

    protected void RegisterProperty(
        Expression<Func<T, Object>> expression)
    {
        Check.Argument(expression, "expression").IsNotNull();

        MemberExpression memberExpression;
        if(ExpressionType.Convert == expression.Body.NodeType)
        {
            var body = (UnaryExpression)expression.Body;
            memberExpression = body.Operand as MemberExpression;
        }
        else
        {
            memberExpression = expression.Body as MemberExpression;
        }

        if(null == memberExpression)
        {
            var message = ResourceLoader<ValueObject<T>>
                              .GetString("InvalidMemberExpression");
            throw new InvalidOperationException(message);
        }

        Properties.Add(memberExpression.Member as PropertyInfo);
    }
}

This generic base class takes care of the equality by overriding Equals and GetHashCode from the Object class and implementing the IEquality interface. It also takes care of a default implementation of the ToString method.

Using this base class significantly reduces the amount of code for implementing  a value object in the domain.

public class Tag : ValueObject<Tag>
{
    public String Name { get; private set; }

    public Tag(String name)
    {
        Name = name;
        RegisterProperty(value => value.Name);
    }
}

And that is that. The only thing I’ve omitted in this example is the validation of the specified name.

I’ve been using this base class in a couple of projects now, and so far, I’ve been very pleased with the results although it can always be improved. I’d love to read your comments.

Published by

Jan Van Ryswyck

Hi, thank you for visiting my blog and reading all the crap that I'm posting here. I'm a senior software engineer at SD WORX. Developing software is one of my greatest passions in life, and I enjoy doing it every single day. I've got three kids (Len, Lisa & Laura) who constantly remind me that there is more in life than just programming all day. They are the greatest kids in the whole world. And last but not least, there's my girlfriend who is my inspiration in life. You can always contact me at jan_dot_van_dot_ryswyck at gmail.com

16 thoughts on “Generic Value Object”

  1. @Gustavo: I tried writing a failing test, but the method doesn’t fail. The line that follows the line of code you mentioned will deal with the otherValue being a null reference.

  2. Excuse me, i didn’t subscribe to the comments and didn’t pay attention you answered.
    This arrives to an exception copying your code and writing in the main of a console app:

    Tag cl1 = new Tag(null);
    Tag cl2 = new Tag(null);

    try
    {
    Console.WriteLine(cl1.Equals(cl2));
    Console.WriteLine(cl2.Equals(cl1));
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex.ToString());
    }

    With my change that doesn’t fail

  3. @Gustavo: You are right, there was a bug in there. I guess I already discovered that earlier on as I still can’t write a failing test. I made a diff between the code in the repository and the code from the blog and found that the post contained the following line:

    if(null == oneValue && null != otherValue) return false;

    while my repository contained:

    if(null == oneValue || null != otherValue) return false;

    The latter seems to fix this issue. Thx a lot for the feedback.

  4. @Jan Van Ryswyck

    I still think Gustavos solution is the right one.

    Your updated repository version:

    if(null == oneValue || null != otherValue) return false;

    Does allways return false when otherValue is not null. And that does not seem right.

    Besides that, I do like your implementation. Thank You!

    -Christian

Comments are closed.