Sortedset не использует собственные равные
Мой класс реализует IEquatable и IComparable. Затем он добавляется в отсортированный набор.
Цель состоит в том, чтобы отсортировать его по свойству "Date" и сделать его равным, если "ID1" и "ID2" совпадают.
Реализованные методы:
public int CompareTo(MyClass other)
{
return other.Date.CompareTo(Date);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = ID1;
hashCode = (hashCode * 397) ^ ID2;
return hashCode;
}
}
public bool Equals(MyClass other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return ID1 == other.ID1
&& ID2 == other.ID2;
}
Результирующий отсортированный набор правильно отсортирован, но все еще есть элементы, которые должны быть равными и, следовательно, не в наборе. При использовании точек останова кажется, что ни GetHashCode, ни Equals не вызываются.
Любые советы о том, как решить эту проблему?
1 ответ
SortedSet
использования CompareTo
для сортировки и сравнения на равенство.
Нет встроенной упорядоченной коллекции, которая позволила бы вам указать другой метод для сравнения на равенство при упорядочении, чем для сравнения на равенство при сохранении отличимости. Я не совсем уверен, почему это так, но это может быть связано с предположениями об алгоритмах, используемых для сортировки.
Если вам нужно такое поведение, возможно, самый простой способ сделать это - обернуть лежащую в основе коллекцию в ее собственный класс, который проверит отличимость перед добавлением новых элементов в коллекцию.
Вы также должны быть осторожны, чтобы элементы, которые равны для сортировки, но не равны по вашему Equals
Метод может быть добавлен в базовую коллекцию. В вашем случае, где сортировка выполняется Date
и равенство достигается ID1
а также ID2
это может выглядеть примерно так:
public int CompareTo(MyClass other)
{
var result = other.Date.CompareTo(Date);
if(result != 0)
return result;
result = other.ID1.CompareTo(ID1);
if(result != 0)
return result;
return other.ID2.CompareTo(ID2);
}
Это налагает дополнительный порядок, если даты совпадают, но я не ожидаю, что это станет проблемой.
В качестве альтернативы, вы можете "обмануть", заставляя элементы, которые равны, сравнивать как равные в позиции сортировки. Это, вероятно, лучше всего перенести в обычай IComparer
потому что это не нормальное поведение сортировки, которое вы хотите, вне SortedSet
:
public int CompareTo(MyClass other)
{
if(other.Equals(this))
return 0;
var result = other.Date.CompareTo(Date);
if(result != 0)
return result;
result = other.ID1.CompareTo(ID1);
if(result != 0)
return result;
return other.ID2.CompareTo(ID2);
}
Это позволит вам избежать создания собственного класса-обертки вокруг коллекции и будет более безопасным. Это довольно хакерский, хотя.