Home > Software design >  Why no warning for GetHashCode() without Equals()
Why no warning for GetHashCode() without Equals()

Time:08-05

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 for GetHashCode()
  • if the GetHashCode() is equal, it is not necessary for them to be the same; this is a collision, and Equals 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 of GetHashCode(). (are Equals() => same GetHashCode())

  • 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 never Equals() anyway (when not overridden) this requirement is automatically fulfilled. (different GetHashCode() => not Equals())

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.

  •  Tags:  
  • c#
  • Related