Реализация Equals
для списка может быть выполнена с помощью метода SequenceEquals
(из пространства имен System.Linq
), который гарантирует, что каждый элемент в одном списке равен элементу с тем же индексом в другом списке.
Одной вещью, которую вы могли бы изменить, однако, является ваша реализация GetHashCode
.Этот метод должен возвращать одно и то же число, если два элемента равны (хотя не гарантируется, что два элемента с одинаковым хеш-кодом равны).Использование base.GetHashCode()
не отвечает этому требованию, поскольку base
в этом случае равно object
;согласно документация , "хеш-коды для ссылочных типов вычисляются путем вызова метода Object.GetHashCode базового класса, который вычисляет хеш-код на основе ссылки на объект" , поэтомуобъекты возвращают один и тот же HashCode, если они ссылаются на один и тот же объект.
HashCode
должен основываться на тех же свойствах, которые используются для определения равенства, поэтому в этом случае мы хотим использовать Prop.GetHashCode()
для классаA
, и мы хотим объединить хеш-код для всех элементов в Prop
для класса B
.
Вот один из способов, которым классы могут быть реорганизованы:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}