IEqualityComparer<T> и пользовательский тип
-
10-12-2019 - |
Вопрос
Я пытаюсь сравнить пользовательский тип в двух List<T>
и используйте Intersect
/ Except
метод.Равенство определяется тремя полями этого типа.Равенство основано на более чем обычном условии (все поля содержат одни и те же данные).Я реализовал, конечно, IEqualityComparer<T>
.Моя проблема в том, что GetHashCode()
метод возвращает не равно, если хеш-код не тот, и это мне не помогает, поскольку в моем случае это не так.
Есть ли способ сравнить два пользовательских объекта, когда равенство основано на более чем одном условии, чтобы я мог использовать пересечение/исключение/отличие и т. д....?
Вот мой код:
public bool Equals(ComparableObject x, ComparableObject y)
{
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
if (Object.ReferenceEquals(x, y))
return true;
if (x.Var1.Equals(y.Var1) && x.Var3.Equals(y.Var3) && !x.Var2.Equals(y.Var2))
return false;
if (x.Var1.Equals(y.Var1) && !x.Var3.Equals(y.Var3) && !x.Var2.Equals(y.Var2))
return true;
if (!x.Var1.Equals(y.Var1) && x.Var3.Equals(y.Var3) && !x.Var2.Equals(y.Var2))
return false;
if (!x.Var1.Equals(y.Var1) && x.Var3.Equals(y.Var3) && x.Var2.Equals(y.Var2))
return true;
if (x.Var1.Equals(y.Var1) && !x.Var3.Equals(y.Var3) && x.Var2.Equals(y.Var2))
return false;
if (!x.Var1.Equals(y.Var1) && !x.Var3.Equals(y.Var3) && x.Var2.Equals(y.Var2))
return false;
if (!x.Var1.Equals(y.Var1) && !x.Var3.Equals(y.Var3) && !x.Var2.Equals(y.Var2))
return false;
return x.Var1.Equals(y.Var1) && x.Var1.Equals(y.Var1) && x.Var3.Equals(y.Var3);
}
public int GetHashCode(ComparableObject x)
{
return obj.Var1.GetHashCode() ^ obj.Var2.GetHashCode()^ obj.Var3.GetHashCode()
}
Решение
Ваша задача – обеспечить такое GetHashCode()
что возвращаемое значение будет различным для объектов, которые являются разные (в как можно большем количестве случаев;вы по-прежнему можете возвращать один и тот же хэш-код для неравных объектов), и он всегда будет одинаковым для объектов, которые может быть равными (во всех случаях;вы не можете возвращать разные хеш-коды для одинаковых объектов).
Например, если одно из трех сравниваемых полей является int
, вы можете вернуть это поле как GetHashCode()
.
Если же сложно придумать что-то умное, можно вернуть константу, например 42
.Сюда Equals()
будет вызываться для всех пар объектов, обеспечивая ожидаемые результаты, хотя и с наименьшей производительностью.
Другие советы
Не уверен, есть ли у вас другие проблемы с GetHashCode в ваших базовых типах, но это пример пользовательского типа и IEqualityComparer, который возвращает true, если только первые два поля одинаковы.Это позволит Except
и т. д.работать над типом.
public class CustomType
{
public int Val1 { get; set; }
public int Val2 { get; set; }
public int Val3 { get; set; }
}
class CustomTypeComparer : IEqualityComparer<CustomType>
{
public bool Equals(CustomType x, CustomType y)
{ return x.Val1 == y.Val1 && x.Val2 == y.Val2; }
public int GetHashCode(CustomType obj)
{ return obj.Val1.GetHashCode() ^ obj.Val2.GetHashCode(); }
}
Если ваши свойства не являются простыми типами, как int
, вы можете использовать Equals()
вместо ==
сравнивать объекты.