Stoyan said:
Hi All,
I don't understand very well this part of MSDN:
"Derived classes that override GetHashCode must also override Equals to
guarantee that two objects considered equal have the same hash code;
otherwise, Hashtable might not work correctly."
For hashtables to operate, the following must be true:
Equals(x,y) -> x.GetHashCode() == y.GetHashCode()
x.GetHashCode() != y.GetHashCode() -> !Equals(x,y)
This effectivly joins the partitioning that Equals imposes on objects
into larger sets, which rather neatly are numbered..., ready to put in
an index'ed array. Cunning thing, hashing
The above makes a constraint on how you can re-define GetHashCode
without redefining Equals.
Stricly speaking, if you use (keep the default) reference-equality the
only constraint on GetHashCode is that it is consistent:
x == y -> x.GetHashCode(x) == y.GetHashCode(y).
Does any one know, why we must also override Equals,
Well, strictly speaking... it's not required, but...
Please give my an example
In short, Hashtables usually does linear comparison, using Equals, of
the lookup key with every entry with the same hash-value modulo the size
of the hashtable. This also shows why choosing a hash-function with good
distribution is very important.
For hashing to be *usefull*, one usually calculates the hashcode on the
basis of the *value* of an object, not the reference, and *that's* why
you need to override Equals.
A minimalistic example:
class Foo {
public readonly int X;
public Foo(int x) { this.X = x; }
public override int GetHashCode() { return X; }
}
If you were to insert Foo's into a hashtable:
IDictionary d = new Hashtable();
Foo foo = new Foo(0);
d.Add(foo, 0);
You would (probably) expect :
Foo foo2 = new Foo(0);
object x = d[foo];
object y = d[foo2];
to both return a boxed 0, but they *dont* foo.GetHashCode() == 0 and
foo2.GetHashCode() == 0, but !Equals(foo, foo2).
So you need to redefine Equals:
public override bool Equals(object other) {
return ((Foo)other).X == X;
}
To do comparison by value, instead of reference.