如何比较泛型类型的值?
如何比较泛型类型的值?
我已将其减少到最小样本:
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
的泛型类型的值?难道它不会以某种方式破坏通用约束的全部目的吗? - 我该如何解决这个问题,或者至少解决这个问题?
(我意识到已经有一些与这个看似简单的问题相关的问题 - 但没有一个线程给出详尽或可行的答案,所以在这里。)
How do I compare values of generic types?
I have reduced it to a minimal sample:
public class Foo<T> where T : IComparable
{
private T _minimumValue = default(T);
public bool IsInRange(T value)
{
return (value >= _minimumValue); // <-- Error here
}
}
The error is:
Operator '>=' cannot be applied to operands of type 'T' and 'T'.
What on earth!? T
is already constrained to IComparable
, and even when constraining it to value types (where T: struct
), we still can't apply any of the operators <
, >
, <=
, >=
, ==
or !=
. (I know that workarounds involving Equals()
exist for ==
and !=
, but it doesn't help for the relational operators).
So, two questions:
- Why do we observe this weird behaviour? What keeps us from comparing the values of generic types which are known to be
IComparable
? Doesn't it somehow defeat the entire purpose of generic constraints? - How do I resolve this, or at least work around it?
(I realize there are already a handful of questions related to this seemingly simple problem - but none of the threads gives an exhaustive or workable answer, so here.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
IComparable
不会重载>=
运算符。你应该使用IComparable
doesn't overload the>=
operator. You should use如果
value
可以为 null,则当前答案可能会失败。使用类似这样的东西:If
value
can be null the current answer could fail. Use something like this instead:运算符重载问题
不幸的是,接口不能包含重载的运算符。尝试在编译器中输入以下内容:
我不知道为什么他们不允许这样做,但我猜这会使语言定义变得复杂,并且用户很难正确实现。
要么是这样,要么是设计师不喜欢滥用的可能性。例如,想象一下对类 MagicMrMeow 进行
>=
比较。或者甚至在类 Matrix
上。这两个值的结果意味着什么?尤其是当可能存在歧义时?官方解决方法
由于上述接口不合法,我们有
IComparable
接口来解决该问题。它不实现任何运算符,并且仅公开一种方法,int CompareTo(T other);
请参阅http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx
int
结果实际上是一个三位或三进制(类似于Boolean
,但具有三种状态)。下表解释了结果的含义:使用解决方法
为了执行与
value >= _minimumValue
相同的操作,您必须改为编写:Problem with operator overloading
Unfortunately, interfaces cannot contain overloaded operators. Try typing this in your compiler:
I don't know why they didn't allow this, but I'm guessing it complicated the language definition, and would be hard for users to implement correctly.
Either that, or the designers didn't like the potential for abuse. For example, imagine doing a
>=
compare on aclass MagicMrMeow
. Or even on aclass Matrix<T>
. What does the result mean about the two values?; Especially when there could be an ambiguity?The official work-around
Since the above interface isn't legal, we have the
IComparable<T>
interface to work around the problem. It implements no operators, and exposes only one method,int CompareTo(T other);
See http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx
The
int
result is actually a tri-bit, or a tri-nary (similar to aBoolean
, but with three states). This table explains the meaning of the results:Using the work-around
In order to do the equivalent of
value >= _minimumValue
, you must instead write:使用 IComparable 泛型时,所有小于/大于运算符都需要转换为对 CompareTo 的调用。无论您使用什么运算符,请保持按相同顺序比较值,并与零进行比较。 (
xy
变为x.CompareTo(y)0
,其中
为>
、>=
等)另外,我建议您使用的通用约束是
where T : IComparable
。 IComparable 本身意味着该对象可以与任何对象进行比较,将一个对象与相同类型的其他对象进行比较可能更合适。When working with IComparable generics, all less than/greater than operators need to be converted to calls to CompareTo. Whatever operator you would use, keep the values being compared in the same order, and compare against zero. (
x <op> y
becomesx.CompareTo(y) <op> 0
, where<op>
is>
,>=
, etc.)Also, I'd recommend that the generic constraint you use be
where T : IComparable<T>
. IComparable by itself means that the object can be compared against anything, comparing an object against others of the same type is probably more appropriate.使用
Comparer
类代替value >= _minimValue
:Instead of
value >= _minimValue
useComparer
class:正如其他人所说,需要显式使用 CompareTo 方法。不能使用带有运算符的接口的原因是,一个类可以实现任意数量的接口,而它们之间没有明确的排名。假设有人试图计算表达式“a = foo + 5;”当 foo 实现了六个接口时,所有这些接口都定义了带有整数第二个参数的运算符“+”;操作员应该使用哪个接口?
类可以派生多个接口这一事实使得接口非常强大。不幸的是,它常常迫使人们更加明确地表达自己真正想做的事情。
As others have stated, one needs to explicitly use the CompareTo method. The reason that one cannot use interfaces with operators is that it is possible for a class to implement an arbitrary number of interfaces, with no clear ranking among them. Suppose one tried to compute the expression "a = foo + 5;" when foo implemented six interfaces all of which define an operator "+" with an integer second argument; which interface should be used for the operator?
The fact that classes can derive multiple interfaces makes interfaces very powerful. Unfortunately, it often forces one to be more explicit about what one actually wants to do.
IComparable
仅强制使用名为CompareTo()
的函数。所以你不能应用你提到的任何运算符IComparable
only forces a function calledCompareTo()
. So you cannot apply any of the operators that you have mentioned我能够使用 Peter Hedberg 的答案为泛型创建一些重载的扩展方法。请注意,
CompareTo
方法在这里不起作用,因为类型T
未知并且不提供该接口。也就是说,我有兴趣看到任何替代方案。--编辑--
我能够通过将所有方法上的
T
限制为IComparable(Of T)
来清理这个问题,如 OP 所示。请注意,此约束也需要类型T
来实现IComparable(Of)
。I was able to use Peter Hedberg's answer to create some overloaded extension methods for generics. Note that the
CompareTo
method doesn't work here, as typeT
is unknown and doesn't present that interface. That said, I'm interested in seeing any alternatives.--EDIT--
I was able to clean this up by constraining
T
toIComparable(Of T)
on all methods, as indicated by OP. Note that this constraint requires typeT
to implementIComparable(Of <type>)
as well.