Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement GetHashCode on a class that has wildcard Equatability

Suppose I want to be able to compare 2 lists of ints and treat one particular value as a wild card.

e.g. If -1 is a wild card, then

{1,2,3,4} == {1,2,-1,4} //returns true

And I'm writing a class to wrap all this logic, so it implements IEquatable and has the relevant logic in public override bool Equals()

But I have always thought that you more-or-less had to implement GetHashCode if you were overriding .Equals(). Granted it's not enforced by the compiler, but I've been under the impression that if you don't then you're doing it wrong.

Except I don't see how I can implement .GetHashCode() without either breaking its contract (objects that are Equal have different hashes), or just having the implementation be return 1.

Thoughts?

like image 297
Brondahl Avatar asked Jul 22 '14 15:07

Brondahl


6 Answers

This implementation of Equals is already invalid, as it is not transitive. You should probably leave Equals with the default implementation, and write a new method like WildcardEquals (as suggested in the other answers here).

In general, whenever you have changed Equals, you must implement GetHashCode if you want to be able to store the objects in a hashtable (e.g. a Dictionary<TKey, TValue>) and have it work correctly. If you know for certain that the objects will never end up in a hashtable, then it is in theory optional (but it would be safer and clearer in that case to override it to throw a "NotSupportedException" or always return 0).

The general contract is to always implement GetHashCode if you override Equals, as you can't always be sure in advance that later users won't put your objects in hashtables.

like image 132
Rich Avatar answered Oct 29 '22 01:10

Rich


In this case, I would create a new or extension method, WildcardEquals(other), instead of using the operators.

I wouldn't recommend hiding this kind of complexity.

like image 29
Dave Bish Avatar answered Oct 29 '22 00:10

Dave Bish


From a logical point of view, we break the concept of equality. It is not transitive any longer. So in case of wildcards, A==B and B==C does not mean that A==C.

From a technical pount of view, returning the same value from GetHashCode() is not somenting unforgivable.

like image 23
AlexD Avatar answered Oct 29 '22 01:10

AlexD


The only possible idea I see is to exploit at least the length, e.g.:

public override int GetHashCode()
{
    return this.Length.GetHashCode()
}
like image 3
BartoszKP Avatar answered Oct 29 '22 02:10

BartoszKP


It's recommended, but not mandatory at all. If you don't need that custom implementation of GetHashCode, just don't do it.

like image 2
Tigran Avatar answered Oct 29 '22 00:10

Tigran


GetHashCode is generally only important if you're going to be storing elements of your class in some kind of collection, such as a set. If that's the case here then I don't think you're going to be able to achieve consistent semantics since as @AlexD points out equality is no longer transitive.

For example, (using string globs rather than integer lists) if you add the strings "A", "B", and "*" to a set, your set will end up with either one or two elements depending on the order you add them in.

If that's not what you want then I'd recommend putting the wildcard matching into a new method (e.g. EquivalentTo()) rather than overloading equality.

like image 2
Joe Lee-Moyet Avatar answered Oct 29 '22 01:10

Joe Lee-Moyet