7 Jun
2009

Generic Value Object

Category:UncategorizedTag: , :

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.

Find me

RSS
Facebook
Twitter
LinkedIn
SOCIALICON
SOCIALICON

Disclaimer

The opinions and content expressed here are my own and not those of my employer.