I've read about 10 different questions on when and how to override GetHashCode
but there's still something I don't quite get. Most implementations of GetHashCode
are based on the hash codes of the fields of the object, but it's been cited that the value of GetHashCode
should never change over the lifetime of the object. How does that work if the fields that it's based on are mutable? Also what if I do want dictionary lookups etc to be based on reference equality not my overridden Equals
?
I'm primarily overriding Equals
for the ease of unit testing my serialization code which I assume serializing and deserializing (to XML in my case) kills the reference equality so I want to make sure at least it's correct by value equality. Is this bad practice to override Equals
in this case? Basically in most of the executing code I want reference equality and I always use ==
and I'm not overriding that. Should I just create a new method ValueEquals
or something instead of overriding Equals
? I used to assume that the framework always uses ==
and not Equals
to compare things and so I thought it was safe to override Equals
since it seemed to me like its purpose was for if you want to have a 2nd definition of equality that's different from the ==
operator. From reading several other questions though it seems that's not the case.
EDIT:
It seems my intentions were unclear, what I mean is that 99% of the time I want plain old reference equality, default behavior, no surprises. For very rare cases I want to have value equality, and I want to explicitly request value equality by using .Equals
instead of ==
.
When I do this the compiler recommends I override GetHashCode
as well, and that's how this question came up. It seemed like there's contradicting goals for GetHashCode
when applied to mutable objects, those being:
a.Equals(b)
then a.GetHashCode()
should == b.GetHashCode()
.a.GetHashCode()
should never change for the lifetime of a
.These seem naturally contradicting when a mutable object, because if the state of the object changes, we expect the value of .Equals()
to change, which means that GetHashCode
should change to match the change in .Equals()
, but GetHashCode
should not change.
Why does there seem to be this contradiction? Are these recommendations not meant to apply to mutable objects? Probably assumed, but might be worth mentioning I'm referring to classes not structs.
Resolution:
I'm marking JaredPar as accepted, but mainly for the comments interaction. To sum up what I've learned from this is that the only way to achieve all goals and to avoid possible quirky behavior in edge cases is to only override Equals
and GetHashCode
based on immutable fields, or implement IEquatable
. This kind of seems to diminish the usefulness of overriding Equals
for reference types, as from what I've seen most reference types usually have no immutable fields unless they're stored in a relational database to identify them with their primary keys.
It's my understanding that the original GetHashCode() returns the memory address of the object, so it's essential to override it if you wish to compare two different objects. EDITED: That was incorrect, the original GetHashCode() method cannot assure the equality of 2 values.
GetHashCode returns a value based on the current instance that is suited for hashing algorithms and data structures such as a hash table. Two objects that are the same type and are equal must return the same hash code to ensure that instances of System.
NO! A hash code is not an id, and it doesn't return a unique value. This is kind of obvious, when you think about it: GetHashCode returns an Int32 , which has “only” about 4.2 billion possible values, and there's potentially an infinity of different objects, so some of them are bound to have the same hash code.
The GetHashCode method provides this hash code for algorithms that need quick checks of object equality. Syntax: public virtual int GetHashCode (); Return Value: This method returns a 32-bit signed integer hash code for the current object.
It doesn't in the sense that the hash code will change as the object changes. That is a problem for all of the reasons listed in the articles you read. Unfortunately this is the type of problem that typically only show up in corner cases. So developers tend to get away with the bad behavior.
As long as you implement an interface like IEquatable<T>
this shouldn't be a problem. Most dictionary implementations will choose an equality comparer in a way that will use IEquatable<T>
over Object.ReferenceEquals. Even without IEquatable<T>
, most will default to calling Object.Equals() which will then go into your implementation.
If you expect your objects to behave with value equality you should override == and != to enforce value equality for all comparisons. Users can still use Object.ReferenceEquals if they actually want reference equality.
What the BCL uses has changed a bit over time. Now most cases which use equality will take an IEqualityComparer<T>
instance and use it for equality. In the cases where one is not specified they will use EqualityComparer<T>.Default
to find one. At worst case this will default to calling Object.Equals
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