Я собираюсь использовать Range
вместо «пользовательской структуры»:
class Range
{
public Range(int from, int to)
{
From = from;
To = to;
}
public int From { get; }
public int To { get; }
}
с использованием IEqualityComparer, но, похоже, не может хорошо работать.
Может быть, потому что "равенство" не может быть тривиально определено приравниванием одного (или обоих) Range
свойств?Но вы (почти) прекрасно определяете равенство ...
x.From == y.To && x.To == y.From
Я думаю, что это должно быть исправлено ...
x.From == y.From && x.To == y.To
Кажется разумным, что два диапазона имеют равные To
и From
равны.
Этого будет достаточно для реализации Equals
метода IEqualityComparer
.
Однако задача реализации GetHashCode
всегда заключается в том, чтосовпадение с Equals
методом - определенное здесь равенство должно приводить к идентичным хешам - но теперь оно основано на свойствах одного экземпляра объекта.
Первый импульс состоит в том, чтобы основать хеш на From + To
.Но это сделало бы range(8,5)
равным range(7,6)
.Эту проблему можно решить, введя From - To
в уравнение.Два диапазона равны, когда From + To
равен и , когда абсолютная разница From - To
равна:
x.From + x.To == y.From + y.To
&& Math.Abs( x.From - x.To) == Math.Abs(y.From - y.To);
Это равенство, основанное на свойствах одного экземпляра с обеих сторонуравнения, так что теперь мы можем реализовать GetHashCode
.Следуя рекомендациям (и помог Resharper):
public int GetHashCode(Range obj)
{
var hashCode = -1781160927;
hashCode = hashCode * -1521134295 + (obj.From + obj.To).GetHashCode();
hashCode = hashCode * -1521134295 + (Math.Abs(obj.From - obj.To)).GetHashCode();
return hashCode;
}
И полный компаратор:
class RangeEqualityComparer : IEqualityComparer<Range>
{
public bool Equals(Range x, Range y)
{
return y != null
&& x != null
&& x.From + x.To == y.From + y.To
&& Math.Abs( x.From - x.To) == Math.Abs(y.From - y.To);
}
public int GetHashCode(Range obj)
{
var hashCode = -1781160927;
hashCode = hashCode * -1521134295 + (obj.From + obj.To).GetHashCode();
hashCode = hashCode * -1521134295 + (Math.Abs(obj.From - obj.To)).GetHashCode();
return hashCode;
}
}
Теперь вы получаете различные диапазоны ...
ranges.OrderBy(r => r.From).Distinct(new RangeEqualityComparer())
Порядок определяет, какой диапазон «равных» диапазонов появится в конечном результате.