I apologize for the shortness of the title, but the actual title would be a bit too long. Here is the actual long title:
Why a warning when overriding Equals()
without GetHashCode()
but no warning when overriding GetHashCode()
without Equals()
?
I also apologize in advance about the fact that this is not a "What is the X of Y" type of question, it is more of an "I observed X; am I missing something?" type of question.
So, consider the following:
class A
{
public override bool Equals( object other ) => true; //warning CS0659
}
class B
{
public override int GetHashCode() => 42; //No warning
}
I am aware of the reasons behind warning CS0659 "class overrides Object.Equals(object o) but does not override Object.GetHashCode()". I do not agree with those reasons, because Equals()
is perfectly viable for a mutable class, whereas such a class must of course never be used as a key in a hash map, and therefore must not have a GetHashCode()
, but my objections are irrelevant, and in any case, receiving a warning which you have no need for is never a problem, because you can always disable it.
It is, however, a problem when you can think of a warning that you would have a use for, but you are not receiving such a warning.
This is what class B
above demonstrates. Overriding GetHashCode()
without also overriding Equals()
is almost certainly a grave mistake, and yet there is no warning. Not by the C# compiler, nor by ReSharper.
Does anyone know why?
Is there something I am missing?
Could it be that the warning exists, but I must know some configuration magic to tease it out of the compiler?
Could it be that I must declare my class in some weird way like public
sealed
albino
or something?
Are there any legitimate reasons for the absence of the warning?
CodePudding user response:
The GetHashCode() method should reflect the Equals
logic; the rules are:
- if two things are equal (
Equals(...) == true
) then they must return the same value forGetHashCode()
- if the
GetHashCode()
is equal, it is not necessary for them to be the same; this is a collision, andEquals
will be called to see if it is a real equality or not.
CodePudding user response:
When you override only the GetHashCode()
method, nothing gets broken or violated (in terms of the Equals()
/GetHashCode()
contract). The Equals()
method still returns true
iff it is the same object and will return false
for every other object. There is no way to break the contract when you override only the GetHashCode()
method.
Two references to the exact same object will return the same
GetHashCode()
since it is in fact the same object and the state of the object hasn't changed in the meantime, as required by the contract ofGetHashCode()
. (areEquals()
=> sameGetHashCode()
)Additionally, when two hash codes are different that means that the two objects must not be
Equals()
to each other. But since two different objects are neverEquals()
anyway (when not overridden) this requirement is automatically fulfilled. (differentGetHashCode()
=> notEquals()
)
As you don't break any contracts, you will not get any warning (unlike warning CS0659 as you mentioned) by the compiler. It is not required that you need to override the Equals()
method in such a case.