如何比较泛型类型的值?
我把它减少到最小样本:
public class Foo<T> where T : IComparable
{
private T _minimumValue = default(T);
public bool IsInRange(T value)
{
return (value >= _minimumValue); // <-- Error here
}
}
错误是:
运算符'&gt; ='不能应用于'T'和'T'类型的操作数。
究竟是什么!? T
已被约束为IComparable
,即使将其约束为值类型(where T: struct
),我们仍然无法应用任何运算符<
,{{1 },>
,<=
,>=
或==
。 (我知道!=
和Equals()
存在涉及==
的变通方法,但它对关系运算符没有帮助。)
所以,有两个问题:
!=
进行比较?它不会以某种方式破坏通用约束的整个目的吗?(我意识到已经有一些与这个看似简单的问题有关的问题了 - 但没有一个线程给出详尽或可行的答案,所以在这里。)
答案 0 :(得分:84)
IComparable
不会使>=
运算符超载。你应该使用
value.CompareTo(_minimumValue) >= 0
答案 1 :(得分:30)
运算符重载问题
不幸的是,接口不能包含重载的运算符。尝试在编译器中输入:
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
结果实际上是三位或三位(类似于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
答案 2 :(得分:19)
如果value
可以为null,则当前答案可能会失败。请改用这样的东西:
Comparer<T>.Default.Compare(value, _minimumValue) >= 0
答案 3 :(得分:6)
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>
。 IComparable本身意味着可以将对象与任何东西进行比较,将对象与相同类型的对象进行比较可能更合适。
答案 4 :(得分:3)
而不是value >= _minimValue
使用Comparer
类:
public bool IsInRange(T value ) {
var result = Comparer<T>.Default.Compare(value, _minimumValue);
if ( result >= 0 ) { return true; }
else { return false; }
}
答案 5 :(得分:2)
正如其他人所说,需要明确使用CompareTo方法。一个人不能使用与运算符的接口的原因是一个类可以实现任意数量的接口,其中没有明确的排名。假设有人试图计算表达式“a = foo + 5;”当foo实现六个接口时,所有接口都定义一个带有整数第二个参数的运算符“+”;哪个接口应该用于运营商?
类可以派生多个接口这一事实使接口非常强大。不幸的是,它往往迫使人们更明确地了解一个人真正想做的事情。
答案 6 :(得分:1)
IComparable
仅强制使用名为CompareTo()
的函数。因此,您不能应用您提到的任何运算符
答案 7 :(得分:0)
我能够使用Peter Hedburg的答案为泛型创建一些重载的扩展方法。请注意,CompareTo
方法在此处不起作用,因为类型T
未知,并且不提供该接口。也就是说,我有兴趣看到任何替代品。
我想在C#中发布,但Telerik的转换器在此代码上失败了。我对C#不太熟悉,无法手动转换它。如果有人愿意做这些荣誉,我很高兴看到相应的编辑。
<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
<强> - 编辑 - 强>
我能够通过将所有方法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