Say you are building a dictionary of data, and you want the key to be a complex object. The easy way would be to do something like this:
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add(someObject.Prop1 + ";" + someObject.Prop2, "some value here");
But that just feels wrong, there are a lot of things that can go wrong. How will this work for objects that have many properties? Is "Prop1.SubProp1,Prop1.SubProp2,Prop1.SubProp3;Prop2.SubProp1,Prop2.SubProp2,Prop2.SubProp3" really the way to go? Maybe if you're building a commissions system for an MLM company or something, but not for real applications. Enter object.GetHashCode()
Here's a link that provides some really good background on GetHashCode():
http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx
Ever wonder why this is a virtual method in the first place? Answered in the article above, quoted below:
I think if we were redesigning the type system from scratch today, hashing might be done differently, perhaps with an IHashable interface. But when the CLR type system was designed there were no generic types and therefore a general-purpose hash table needed to be able to store any object.
Okay, so how to implement a decent GetHashCode() method yourself? Here is a very smart guy's answer:
http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode/263416#263416
Code excerpt from the link:
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
This works pretty well, and any time you have prime numbers in your code people will think you're hardcore. Or they'll recognize that you copied the code from stackoverflow.com, but it's from the #1 user there, so you're good.
What to do with null fields though? Be careful with that one, one suggestion I found while doing a search made it seem like it was okay to use base.GetHashCode if one of your fields is null. Try to view the implementation of object.GetHashCode() using Reflector (or some other tool, since reflector is bugging me about the free version expiring). You'll see there that the implementation is internal in the CLR code. But this guy has it all figured out:
http://stackoverflow.com/questions/720177/default-implementation-for-object-gethashcode/720196#720196
But basically what we need to understand about object.GetHashCode() is that it returns a unique code for the object, so two "equal" objects will NOT have the same code. So, not what you want to use if you have null fields. Just use 0 in that case:
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Example of how to deal with a null field
hash = hash * 23 + (field1 == null ? 0 : field1.GetHashCode());
// not this way
// hash = hash * 23 + (field1 == null ? base.GetHashCode() : field1.GetHashCode());
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}