Should we override both Equals
and GetHashCode
properties when implementing a custom class instances comparison?
In the following code I have a collection of classes. The class A
is compared by the ID
, the class B
- by Code
.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
List<I> bars = new List<I>();
bars.Add(new A() { Id = 1, Code = "one A" });
bars.Add(new B() { Id = 1, Code = "one B" });
bars.Add(new A() { Id = 1, Code = "one A+" });
bars.Add(new B() { Id = 1, Code = "one B" }); // Code = "one B+"
var distictBars = bars.Distinct();
foreach (var item in distictBars)
{
Debug.WriteLine(item.Code);
}
}
}
interface I
{
string Code { get; set; }
}
class A : I, IEquatable<A>
{
public int Id { get; set; }
public string Code { get; set; }
public bool Equals(A other)
{
// this is the ??? comparison
return this.Id == other.Id;
//return this.Code == other.Code;
}
public override bool Equals(object obj)
{
if (obj is A)
return this.Equals(obj as A);
else
return object.ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
// this is the wanted comparison
return this.Id;
}
}
class B : I, IEquatable<B>
{
public int Id { get; set; }
public string Code { get; set; }
public bool Equals(B other)
{
// this is the ??? comparison
return this.Id == other.Id;
}
public override bool Equals(object obj)
{
if (obj is B)
return this.Equals(obj as B);
else
return object.ReferenceEquals(this, obj);
}
public override int GetHashCode()
{
// this is the wanted comparison
return this.Code.GetHashCode();
}
}
}
The output is:
one A
one B
in case the commented Code = "one B+"
the output is
one A
one B
one B+
Now I ask myself what for should I override the Equals
in the B
class if it seems that this have no effect on comparison?
Is GetHasCode()
overriding sufficient for that kind of comparisons?
In Java, the == operator compares that two references are identical or not. Whereas the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity.
It is because the framework requires that two objects that are the same must have the same hashcode. If you override the equals method to do a special comparison of two objects and the two objects are considered the same by the method, then the hash code of the two objects must also be the same.
Comparing Objects ¶ When using the comparison operator ( == ), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with == ), and are instances of the same class.
The value returned by hashCode() is the object's hash code, which is the object's memory address in hexadecimal. equals() checks if the two object references are same. If two objects are equal then their hashCode must be the same, but the reverse is not true.
Here's what you need to understand about the relationship between Equals
and GetHashCode
.
Hash codes are used by hashtables to quickly find a "bucket" in which an element is expected to exist. If elements are in two different buckets, the assumption is they cannot be equal.
The outcome of this is that you should view a hash code, for purposes of determining uniqueness, as a quick negative check: i.e., if two objects have different hash codes, they are not the same (regardless of what their Equals
methods return).
If two objects have the same hash code, they will reside in the same bucket of a hash table. Then their Equals
methods will be called to determine equality.
So GetHashCode
must return the same value for two objects that you want to be considered equal.
The Distinct
method will use the GetHashCode
method to determine inequality between the items, and the Equals
method to determine equality.
It first make a fast comparison using the hash code to determine which items are definitely not equal, i.e. have different hash codes, then it compares the items that have the same hash code to determine which are really equal.
In your implementation of the B
class you have an inconsistent implementation of the GetHashCode
and Equals
method, so the comparison won't work properly. Your two B
objects have different hash codes, so they won't be compared to each other. Two items that are considered to be equal should also return the same hash code.
If a class implements the IEquatable<T>
interface, the Equals(T)
method will be used, otherwise the Equals(object)
method is used.
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