Равно vs GetHashCode при сравнении объектов
должны ли мы переопределить оба Equals
и GetHashCode
свойства при реализации сравнения экземпляров пользовательского класса?
в следующем коде у меня есть коллекция классов. Класс!--5--> по сравнению с ID
класс 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();
}
}
}
выход:
one A
one B
в случае с комментарием Code = "one B+"
выход
one A
one B
one B+
теперь я спрашиваю себя, для чего я должен переопределить Equals
на B
класс, если кажется, что это не влияет на сравнение?
Is GetHasCode()
переопределение, достаточное для такого рода сравнений?
3 ответов
вот что вам нужно понять о взаимоотношениях между Equals
и GetHashCode
.
хэш-коды используются хэш-таблицами, чтобы быстро найти "ведро", в котором, как ожидается, будет существовать элемент. если элементы находятся в двух разных ведрах, предполагается, что они не могут быть равны.
результатом этого является то, что вы должны смотреть хэш-код, для определения уникальности, как быстро отрицательный проверка: т. е. если два объекта имеют разные хэш-коды, они не то же самое (независимо от того, что их Equals
методы возвращают).
если два объекта имеют то же самое хэш-код, они будут находиться в одном ведре хэш-таблицы. затем их Equals
методы будут вызываться для определения равенства.
так GetHashCode
должны возвращает одно и то же значение для двух объектов, которые вы хотите считать равными.
на Distinct
метод будет использовать GetHashCode
метод определения неравенства между элементами, и Equals
метод для определения равенства.
сначала сделайте быстрое сравнение, используя хэш-код, чтобы определить, какие элементы определенно не равны, т. е. имеют разные хэш-коды, затем он сравнивает элементы, имеющие один и тот же хэш-код, чтобы определить, какие из них действительно равны.
в реализации B
класс у вас непоследовательный реализация GetHashCode
и Equals
метод, поэтому сравнение не будет работать должным образом. Ваши двое!--3--> объекты имеют разные хэш-коды, поэтому они не будут сравнивать друг с другом. Два элемента, которые считаются равными, также должны возвращать один и тот же хэш-код.
если класс реализует IEquatable<T>
интерфейс Equals(T)
метод будет использоваться, в противном случае метод.
вам всегда нужно переопределить их вместе и с совместимых реализаций. Совпадение/несоответствие хэш-кода означает (соответственно)"возможно равенство" и "неравенство". Хэш-код сама по себе не указывает на равенство. Следовательно, после того, как найдено совпадение хэш-кода (или используется для создания групп значений),Equals
по-прежнему проверяется для определения соответствия.
Если два не согласны, вы можете никогда не найти спички.