Объекты в c# обычно сравниваются по ссылке , а не по значению . Это означает, что new object() != new object()
. Точно так же new List<int>() { 1 } != new List<int>() { 1 }
. Структуры и примитивы, с другой стороны, сравниваются по значению , а не по ссылке.
Некоторые объекты переопределяют свой метод равенства вместо сравнения значений. Например, строки: new string(new[] { 'a', 'b', 'c'}) == "abc"
, даже если object.ReferenceEquals(new string(new[] { 'a', 'b', 'c'}), "abc") == false
.
Но коллекции, списки, массивы и т. Д. c. не делайте. Не зря - сравнивая два списка целых, что вы хотите сравнить? Точные элементы, независимо от порядка? Точные элементы в порядке? Сумма элементов? Там не один ответ, который подходит всем. И часто вам, возможно, захочется проверить, есть ли у вас один и тот же объект.
При работе с коллекциями или LINQ вы часто можете указать пользовательский «компаратор», который будет обрабатывать сравнения так, как вы хотите. Затем методы сбора данных используют этот «компаратор» всякий раз, когда ему нужно сравнить два элемента.
Очень простой компаратор, работающий на ReadOnlyCollection<T>
, может выглядеть следующим образом:
class ROCollectionComparer<T> : IEqualityComparer<IReadOnlyCollection<T>>
{
private readonly IEqualityComparer<T> elementComparer;
public ROCollectionComparer() : this(EqualityComparer<T>.Default) {}
public ROCollectionComparer(IEqualityComparer<T> elementComparer) {
this.elementComparer = elementComparer;
}
public bool Equals(IReadOnlyCollection<T> x, IReadOnlyCollection<T> y)
{
if(x== null && y == null) return true;
if(x == null || y == null) return false;
if(object.ReferenceEquals(x, y)) return true;
return x.Count == y.Count &&
x.SequenceEqual(y, elementComparer);
}
public int GetHashCode(IReadOnlyCollection<T> obj)
{
// simplistic implementation - but should OK-ish when just looking for equality
return (obj.Count, obj.Count == 0 ? 0 : elementComparer.GetHashCode(obj.First())).GetHashCode();
}
}
И затем Вы можете сравнить поведение проверки на равенство по умолчанию и вашей пользовательской проверки:
var std = new HashSet<int[]>(new[] { new[] { 1, 2 }, new[] { 2, 2}});
std.ExceptWith(new[] { new[] { 2, 2}});
std.Dump();
var custom = new HashSet<int[]>(new[] { new[] { 1, 2 }, new[] { 2, 2 } }, new ROCollectionComparer<int>());
custom.ExceptWith(new[] { new[] { 2, 2 }});
custom.ExceptWith(new[] { new int[] { }});
custom.Dump();
Все это можно проверить в этой скрипке .