June 6th, 2011

Implementing a Value-Object Base class (Supertype pattern–DDD patterns related)

Cesar De la Torre
Principal Program Manager

It is usually a recommended practice to have Value-Object base-class so we can have common functionality which can be used by all of our value-object classes. Typically, comparison methods or any other common subject for Value-Objects, should be included here.

Below I show a sample Value-Object Base-Class:

public class ValueObject<TValueObject> : IEquatable<TValueObject>
    where TValueObject : ValueObject<TValueObject>
{
    
public bool Equals(TValueObject other)
{
    if ((object)other == null)
        return false;

    //compare all public properties
    PropertyInfo[] publicProperties = this.GetType().GetProperties();

    if ((object)publicProperties != null
        &&
        publicProperties.Any())
    {
        bool result = true;
        foreach (var item in publicProperties)
        {
            //compare two values using default equatable method
            if (!item.GetValue(this, null).Equals(item.GetValue(other, null)))
            {
                result = false;
                break;
            }
        }

        return result;
    }
    else
        return true;
}

public override bool Equals(object obj)
{
    if ((object)obj == null)
        return false;

    ValueObject<TValueObject> item = obj as ValueObject<TValueObject>;

    if ((object)item != null)
        return Equals((TValueObject)item);
    else
        return false;

}

public override int GetHashCode()
{
    int hashCode = 31;
    bool changeMultiplier = false;
    int index = 1;

    //compare all public properties
    PropertyInfo[] publicProperties = this.GetType().GetProperties();

    if ((object)publicProperties != null
        &&
        publicProperties.Any())
    {
        foreach (var item in publicProperties)
        {
            object value = item.GetValue(this, null);

            if ((object)value != null)
            {

                hashCode = hashCode * ((changeMultiplier) ? 59 : 114) + value.GetHashCode();

                changeMultiplier = !changeMultiplier;
            }
            else
                hashCode = hashCode ^ (index * 13);//only for support {"a",null,null,"a"} <> {null,"a","a",null}
        }
    }

    return hashCode;
}

public static bool operator ==(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
    // If both are null, or both are same instance, return true.
    if (System.Object.ReferenceEquals(x, y))
    {
        return true;
    }

    // If one is null, but not both, return false.
    if (((object)x == null) || ((object)y == null))
    {
        return false;
    }

    // Return true if the fields match:

    return x.Equals(y);

}

public static bool operator !=(ValueObject<TValueObject> x, ValueObject<TValueObject> y)
{
    return !(x == y);
}
}

Author

Cesar De la Torre
Principal Program Manager

Principal Program Manager at the Azure team.

0 comments

Discussion are closed.