Recently I witness many mistakes when creating new class. many developers override Object.GetHashCode() in a wrong way!!! that can make error that will be very hard to find. Lets start with the basic rules when writing your own GetHashCode:
- If X.Eqauls(Y) == true then X.GetHashCode() == Y.GetHashCode(). if two objects are equals they must have the same HashCode.
- If X.GetHashCode() != Y.GetHashCode() then X.Equals(Y) == false. If two objects has defraent hash code they cant be Equal to each other.
- object GetHashCode() must NOT be changed during it life cycle. Once the object was created it hash code must NOT change!!!
- If X.Eqauls(Y) == false then X.GetHashCode() Should (NOT A MUST) be defrant from Y.GetHashCode()
Here is an example of a wrong way to make HashCode and what will happen:
class MyWrongObject
{
private int m_One;
public int One
{
get { return m_One; }
set { m_One = value; }
}
public MyWrongObject() { }
public MyWrongObject(int one)
{
m_One = one;
}
public override bool Equals(object obj)
{
MyWrongObject other = obj as MyWrongObject;
if (other != null)
return (One == other.One);
else
return false;
}
public override string ToString()
{
return String.Format("MyWrongObject[{0}]", One);
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
public static void Main(string[] args)
{
HashSet<MyWrongObject> set1 = new HashSet<MyWrongObject>();
MyWrongObject obj1 = new MyWrongObject(1, 1);
set1.Add(obj1);
if (set1.Contains(obj1))
Console.WriteLine("Found obj1");
obj1.One = 2; // This line changes the GetHashCode() of obj1
if (set1.Contains(obj1))
{
// We wont see this line because Contains looks at the GetHashCode()
then at Equals()
Console.WriteLine("You won't see this line");
}
else
Console.WriteLine("Hmmm.. can't find obj1 but obj1 is here");
foreach (MyWrongObject obj in set1)
{
if (obj1.Equals(obj))
Console.WriteLine("obj:{0} Can't find obj1 but obj1 is here", obj);
}
}
}
Please notice that you can't make a setter to a member that changes the GetHashCode() of the object.
If you do that you should think about throwing an exeption when using GetHashCode()
Enjoy,
1 comment:
I loved this post and this blog.
Have a nice weekend
Post a Comment