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?
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.
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.
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.
The only possible idea I see is to exploit at least the length, e.g.:
public override int GetHashCode()
{
return this.Length.GetHashCode()
}
It's recommended, but not mandatory at all. If you don't need that custom implementation of GetHashCode
, just don't do it.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With