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. Stirling job. Nice Jan, I’ve been using Jimmy’s implementation for a while now too. A generic base VO is certainly a real time saver!

    Perhaps an ‘auto’ registration (all public properties) by default, would be useful? Or a void RegisterAllPuplicProperties(this) member?

    I’m not going to change VO impl part way through a project, but I’m tagging in delicious and will return back, post-current-project.

  2. If one value is null and other values is not your function will crash.
    It should had been something like:

    if (oneValue == null) return otherValue == null;

  3. Well, the previous comment should have started by saying i liked your work. I liked the static reflection here, and i took some parts of it. I just put attention on what a i previously commented.

    Gustavo.

  4. Quality of the code aside, I don’t understand why others have stamped the idea of reflecting an object as belonging to this guy or that guy. Soon enough we’re gonna see software patents on these things. I’ve been using a similar pattern independently; heck, I actually reflect on the type upon type initialization, to cut some of the cost; Java has used dynabeans for a long time, but neither me nor the guys at Apache will claim co-authorship.

    I guess this will slowly launch us in a frenzy of patenting our simplest bits of code on our blogs. It’s a bit like the frenzy with Joel Spolsky’s “Law of Leaky Abstractions” which is a piece of crap but I’ve seen it quoted quite a few times. Suddenly, the stupidest of bloggers could claim they’ve recognized a subtle law in some aspect of their work.

    Look. The GoF didn’t claim they invented the patterns. They but cataloged them. The DDD community shouldn’t claim to have popularized the Value Object, except maybe to the .NET programmers. And this or that way of doing generic value objects aren’t this or that guy’s idea; they’re age old by now, really.

    Thanks for posting per my right to dissent and to keep our put into our less wary readers some sense of personality.

  5. @Mihai: I thought I made myself clear that I didn’t invent anything and that there are other people (Jimmy Bogard amongst others) who are doing this and have similar code. I’m also not claiming any ownership of the pattern. I just wanted to share some code that might be helpful to others and maybe get some feedback in the process. Lighten up.

Comments are closed.