I have implemented the class below:
public class carComparer : IEqualityComparer<Car>
{
public bool Equals(Car car1, Car car2)
{
if (car1 == null || car2 == null)
return false;
return (car1.description == car2.description);
}
public int GetHashCode(Car car)
{
unchecked
{
int hash = 17;
hash = hash * 29 + car.id.GetHashCode();
hash = hash * 29 + car.description.GetHashCode();
return hash;
}
}
}
Now see this:
Car p1 = new Car() { id = Guid.NewGuid(), description = "Test1" };
Car p2 = new Car() { id = Guid.NewGuid(), description = "Test1" };
Car p3 = new Car() { id = Guid.NewGuid(), description = "Test1" };
Car p4 = new Car() { id = Guid.NewGuid(), description = "Test1" };
var hash = new HashSet<Car>();
hash.Add(p1);
hash.Add(p2);
var hash2 = new HashSet<Car>();
hash2.Add(p3);
hash2.Add(p4);
var carComparer = new CarComparer();
Assert.That(hash, Is.EquivalentTo(hash2).Using(carComparer));
I put breakpoints in .equals and .hashcode. Equals is used; but GetHashCode is not. Why?
You are comparing two HashSet
using NUnit Is.EquivalentTo
. There is no reason for it to call GetHashCode
- it basically compares two collections for equality of its members. That's why GetHashCode
is never called and Equals
is called to compare two items from different HashSet
s for equality. Your hashsets could as well be lists or any other enumerable - that doesn't change anything when comparing two collections.
You might expect GetHashCode
to be called when you add item to HashSet
- but it's not so, because at this point your carComparer
is not yet known - you don't pass it to HashSet
constructor. If you will do it like this:
var hash = new HashSet<Car>(new carComparer());
Then GetHashCode
would be called when you add new item to corresponding HashSet
.