views:

253

answers:

3

I'm working with a domain model and was thinking about the various ways that we have to implement this two methods in .NET. What is your preferred strategy?

This is my current implementation:

    public override bool Equals(object obj)
    {
        var newObj = obj as MyClass;

        if (null != newObj)
        {
            return this.GetHashCode() == newObj.GetHashCode();
        }
        else
        {
            return base.Equals(obj);
        }
    }

    //Since this is an entity I can use it´s Id
    //When I don´t have an Id I usually make a composite key of the properties
    public override int GetHashCode()
    {
        return String.Format("MyClass{0}", this.Id.ToString()).GetHashCode();
    }
A: 

Assuming that the instances are equal because the hash codes are equal is wrong.

I guess your implementation of GetHashCode is OK, but I usually use things similar to this:

public override int GetHashCode() {
    return object1.GetHashCode ^ intValue1 ^ (intValue2 << 16);
}
erikkallen
+1  A: 

Hashcodes can collide so I don't think they are a good way to compare equality. You should compare the underlying values that make the objects "equal" instead. See @Jon Skeet's answer to this question: http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode for a better GetHashCode implementation if your equality encompasses several properties. If it's just a single property, you can just reuse it's hashcode.

tvanfosson
+4  A: 

Domain-Driven Design makes the distinction between Entities and Value Objects. This is a good distinction to observe since it guides how you implement Equals.

Entities are equal if their IDs equal each other.

Value Objects are equal if all their (important) constituent elements are equal to each other.

In any case, the implementation of GetHashCode should base itself on the same values that are used to determine equality. In other words, for Entities, the hash code should be calculated directly from the ID, whereas for Value Objects it should be calculated from all the constituent values.

In any case, I often find it valuable to implement IEquatable<T>. Not that it gives us much, but it signals that the type in question has custom equality behavior.

Mark Seemann