В.NET алгоритм BinarySearch (в Списках, Массивах, и т.д.), кажется, перестал работать, если объекты, которые Вы пытаетесь искать, наследовались IComparable вместо того, чтобы реализовать его непосредственно:
List<B> foo = new List<B>(); // B inherits from A, which implements IComparable<A>
foo.Add(new B());
foo.BinarySearch(new B()); // InvalidOperationException, "Failed to compare two elements in the array."
Где:
public abstract class A : IComparable<A>
{
public int x;
public int CompareTo(A other)
{
return x.CompareTo(other.x);
}
}
public class B : A {}
Существует ли путь вокруг этого? Реализация CompareTo (B другой) в классе B, кажется, не работает.
В документации это довольно ясно сказано:
проверяет, реализует ли тип T универсальный интерфейс IComparable и использует ли эту реализацию, если она доступна. Если нет, Comparer.Default проверяет, реализует ли тип T интерфейс IComparable. Если тип T не реализует ни один интерфейс, Comparer.Default генерирует исключение InvalidOperationException.
Итак, простое решение - реализовать неуниверсальный интерфейс IComparable
.
Добавление CompareTo (B other)
будет работать для вас, если вы также реализуете IComparable
- вы, вероятно, забыли этот бит .
Интересным решением является компиляция кода с использованием C # 4, где он выполняется без ошибок. C # 4 представляет Generic Covariance: открытый интерфейс IComparable <в T>
vs открытый интерфейс IComparable
, и опубликованный код работает, как ожидалось.
Верно, проблема в том, что он пытается проверить, реализует ли класс B
IComparable
, чего не делает, потому что он фактически реализует IComparable
, затем пытается IComparable
, после чего отказывается. Как указал Коби, реализация неуниверсального IComparable
решит эту проблему.