Ответ 1
IComparable
не перегружает оператор >=
. Вы должны использовать
value.CompareTo(_minimumValue) >= 0
Как сравнить значения общих типов?
Я уменьшил его до минимального образца:
public class Foo<T> where T : IComparable
{
private T _minimumValue = default(T);
public bool IsInRange(T value)
{
return (value >= _minimumValue); // <-- Error here
}
}
Ошибка:
Оператор ' > =' не может применяться к операндам типа "T" и "T".
Что на свете!? T
уже привязан к IComparable
, и даже когда он привязывает его к типам значений (where T: struct
), мы по-прежнему не можем применять ни один из операторов <
, >
, <=
, >=
, ==
или !=
. (Я знаю, что обходные пути с участием Equals()
существуют для ==
и !=
, но это не помогает для реляционных операторов).
Итак, два вопроса:
IComparable
? Разве это не может каким-то образом превзойти всю цель общих ограничений?(Я понимаю, что есть уже несколько вопросов, связанных с этой, казалось бы, простой проблемой, но ни один из потоков не дает исчерпывающего или работоспособного ответа, поэтому здесь.)
IComparable
не перегружает оператор >=
. Вы должны использовать
value.CompareTo(_minimumValue) >= 0
Проблема с перегрузкой оператора
К сожалению, интерфейсы не могут содержать перегруженные операторы. Попробуйте ввести это в свой компилятор:
public interface IInequalityComaparable<T>
{
bool operator >(T lhs, T rhs);
bool operator >=(T lhs, T rhs);
bool operator <(T lhs, T rhs);
bool operator <=(T lhs, T rhs);
}
Я не знаю, почему они этого не допустили, но я предполагаю, что это осложняет определение языка, и было бы сложно правильно реализовать пользователей.
Либо это, либо дизайнеры не любят возможности злоупотребления. Например, представьте, что вы выполняете сравнение >=
на class MagicMrMeow
. Или даже на class Matrix<T>
. Что означает результат относительно двух значений?; Особенно, когда может быть двусмысленность?
Официальная работа
Так как вышеупомянутый интерфейс не является законным, у нас есть интерфейс IComparable<T>
, чтобы обойти проблему. Он не выполняет операторов и предоставляет только один метод, int CompareTo(T other);
См. http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx
Результат int
на самом деле является трехбитным или трехзначным (похожим на a Boolean
, но с тремя состояниями). В этой таблице объясняется значение результатов:
Value Meaning
Less than zero This object is less than
the object specified by the CompareTo method.
Zero This object is equal to the method parameter.
Greater than zero This object is greater than the method parameter.
Использование рабочей области
Чтобы сделать эквивалент value >= _minimumValue
, вы должны написать:
value.CompareTo(_minimumValue) >= 0
Если value
может быть пустым, текущий ответ может завершиться неудачно. Вместо этого используйте что-то вроде этого:
Comparer<T>.Default.Compare(value, _minimumValue) >= 0
public bool IsInRange(T value)
{
return (value.CompareTo(_minimumValue) >= 0);
}
При работе с генерируемыми IComparable все меньше или больше операторов необходимо преобразовать в вызовы CompareTo. Независимо от того, какой оператор вы будете использовать, сохраните значения, сравниваемые в том же порядке, и сравните их с нулем. (x <op> y
становится x.CompareTo(y) <op> 0
, где <op>
- >
, >=
и т.д.)
Кроме того, я бы рекомендовал, чтобы общее ограничение, которое вы используете, было where T : IComparable<T>
. Само по себе несогласное означает, что объект можно сравнить с чем-либо, более вероятно, что сравнение объекта с другими подобным типом является более подходящим.
Вместо value >= _minimValue
используйте Comparer
класс:
public bool IsInRange(T value ) {
var result = Comparer<T>.Default.Compare(value, _minimumValue);
if ( result >= 0 ) { return true; }
else { return false; }
}
IComparable
создает только функцию с именем CompareTo()
. Таким образом, вы не можете применять ни один из операторов, о которых вы упоминали
Как утверждали другие, нужно явно использовать метод CompareTo. Причина, по которой нельзя использовать интерфейсы с операторами, заключается в том, что класс может реализовать произвольное количество интерфейсов, без четкого ранжирования среди них. Предположим, что кто-то попытался вычислить выражение "a = foo + 5;" когда foo реализовал шесть интерфейсов, все из которых определяют оператор "+" с целым вторым аргументом; какой интерфейс должен использоваться для оператора?
Тот факт, что классы могут выводить несколько интерфейсов, делает интерфейсы очень мощными. К сожалению, это часто заставляет говорить более четко о том, что на самом деле хочет сделать.
Я смог использовать ответ Питера Хедбурга, чтобы создать некоторые перегруженные методы расширения для дженериков. Обратите внимание, что метод CompareTo
здесь не работает, поскольку тип T
неизвестен и не отображает этот интерфейс. Тем не менее, меня интересуют любые альтернативы.
Я хотел бы опубликовать на С#, но конвертер Telerik не работает в этом коде. Я недостаточно хорошо знаком с С#, чтобы надежно преобразовать его вручную. Если кто-то захочет делать почести, я был бы рад увидеть, что это отредактировано соответствующим образом.
<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T))
Instance.RemoveDuplicates(Function(X, Y) Comparer(Of T).Default.Compare(X, Y))
End Sub
<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparison As Comparison(Of T))
Instance.RemoveDuplicates(New List(Of Comparison(Of T)) From {Comparison})
End Sub
<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparisons As List(Of Comparison(Of T)))
Dim oResults As New List(Of Boolean)
For i As Integer = 0 To Instance.Count - 1
For j As Integer = Instance.Count - 1 To i + 1 Step -1
oResults.Clear()
For Each oComparison As Comparison(Of T) In Comparisons
oResults.Add(oComparison(Instance(i), Instance(j)) = 0)
Next oComparison
If oResults.Any(Function(R) R) Then
Instance.RemoveAt(j)
End If
Next j
Next i
End Sub
- EDIT -
Мне удалось очистить это, сдерживая T
до IComparable(Of T)
для всех методов, как указано OP. Обратите внимание, что для этого ограничения требуется тип T
для реализации IComparable(Of <type>)
.
<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T As IComparable(Of T))(Instance As List(Of T))
Instance.RemoveDuplicates(Function(X, Y) X.CompareTo(Y))
End Sub