Sunday, June 07, 2009

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.

8 comments:

desfen said...

Dag Jan :-)

Doesn't this implementation of GetHashCode() violate one of the rules MS has laid down wrt implementing it ? I'm thinking of the rule that the hashcode of an object shouldn't change when one of its properties is changed.

You obviously don't see this as a problem so I'm interested to hear your thoughts on this.

Sven

Jan Van Ryswyck said...

You'll be fine using this implementation because the whole point of value objects is that they are immutable. A new value, means a new object.

Entities on the other hand always rely on identity instead of value. Entities may never, ever derive from the base class discussed in this post. Maybe I'll post my DomainEntity base class in one of the next posts. Anyway, in order to get the hash code of an entity, the implementation has to use the ID because it never changes. Another ID is another entity.

I certainly recommend reading the blue book (DDD - Eric Evans) for a more thorough explanation. Hope this helps.

desfen said...

D'oh ! Of course, for value objects this is perfectly acceptable. Thanks for setting me straight.

Jan Van Ryswyck said...

You're welcome :-)

Stiiifff said...

Hi Jan,

I also gave a thought about that subject and I came to the conclusion that while the base class approach is fine, I still would prefer to implement it using a Mixin.

Which means either use DynamicProxy or have first class support for Mixins in the .Net Framework ;)

We could then share reusable libraries of completely generic mixins ... instead of so many people re-writing their own base class for value object, entity, repository, generic equality, gethashcode, ... (and the list goes on).

You might reply me that 'Reuse is a fallacy' ... but I think that in those particular cases, it would make sense.

Btw, I'm still surprised there's no class library or framework in .Net defining the standard interfaces & components for DDD.

Jan Van Ryswyck said...

Mixins are a viable option as well, and their use can be considered although a simple base class has its place as well. Too bad mixins aren't that well known in the .NET space and that the CLR doesn't have support for them.

I think that DDD support in the .NET FW is not a goal of Microsoft as they target themselves as a platform provider. Before adding DDD support, they should first try to understand what DDD is and what it stands for. Based on the P&P guidance available today, I think they don't even have a clue ;-).

hrerikl said...

Sorry For The Late Comments, but I am curious what library the Check and ResourceLoader Methods Are from?

Jan Van Ryswyck said...

Check is just part of my own Design by Contract library. You can use any other open-source alternative or the one from Microsoft. ResourceLoader is a helper class from a utilities project on CodePlex. This loads a string from a resource file, in this case an error message.