本文翻译自:Can't operator == be applied to generic types in C#?
According to the documentation of the ==
operator in MSDN , 根据MSDN中 ==
运算符的文档,
For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. 对于预定义的值类型,相等运算符(==)如果其操作数的值相等,则返回true,否则返回false。 For reference types other than string, == returns true if its two operands refer to the same object. 对于字符串以外的引用类型,如果==的两个操作数引用同一对象,则==返回true。 For the string type, == compares the values of the strings. 对于字符串类型,==比较字符串的值。 User-defined value types can overload the == operator (see operator). 用户定义的值类型可能会使==运算符重载(请参阅运算符)。 So can user-defined reference types, although by default == behaves as described above for both predefined and user-defined reference types. 用户定义的引用类型也可以,尽管默认情况下==的行为与上述预定义和用户定义的引用类型相同。
So why does this code snippet fail to compile? 那么,为什么此代码片段无法编译?
bool Compare(T x, T y) { return x == y; }
I get the error Operator '==' cannot be applied to operands of type 'T' and 'T' . 我收到错误运算符'=='不能应用于类型'T'和'T'的操作数 。 I wonder why, since as far as I understand the ==
operator is predefined for all types? 我不知道为什么,因为据我了解, ==
运算符已为所有类型预定义?
Edit: Thanks, everybody. 编辑:谢谢大家。 I didn't notice at first that the statement was about reference types only. 起初我没有注意到该声明仅涉及引用类型。 I also thought that bit-by-bit comparison is provided for all value types, which I now know is not correct. 我还认为为所有值类型提供了逐位比较,现在我知道这是不正确的。
But, in case I'm using a reference type, would the ==
operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one? 但是,如果我使用的是引用类型,则==
运算符会使用预定义的引用比较,还是如果一个类型定义了一个比较类型,它将使用运算符的重载版本吗?
Edit 2: Through trial and error, we learned that the ==
operator will use the predefined reference comparison when using an unrestricted generic type. 编辑2:通过反复试验,我们了解到==
运算符在使用不受限制的泛型类型时将使用预定义的引用比较。 Actually, the compiler will use the best method it can find for the restricted type argument, but will look no further. 实际上,编译器将使用它可以为受限类型参数找到的最佳方法,但是不再赘述。 For example, the code below will always print true
, even when Test.test(new B(), new B())
is called: 例如,即使Test.test(new B(), new B())
下面的代码也将始终显示true
:
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test(T a, T b) where T : A { Console.WriteLine(a == b); } }
参考:https://stackoom.com/question/1dgq/运算符-不能应用于C-中的泛型类型吗
There is an MSDN Connect entry for this here 没有此的MSDN连接进入这里
Alex Turner's reply starts with: Alex Turner的回复开始于:
Unfortunately, this behavior is by design and there is not an easy solution to enable use of == with type parameters that may contain value types. 不幸的是,这种行为是设计使然,没有一个简单的解决方案就可以将==与可能包含值类型的类型参数一起使用。
I wrote the following function looking at the latest msdn. 我编写了以下函数,以查看最新的msdn。 It can easily compare two objects x
and y
: 它可以轻松比较两个对象x
和y
:
static bool IsLessThan(T x, T y)
{
return ((IComparable)(x)).CompareTo(y) <= 0;
}
The compile can't know T couldn't be a struct (value type). 编译器无法知道T不能是结构(值类型)。 So you have to tell it it can only be of reference type i think: 所以你必须告诉它它只能是我认为的引用类型:
bool Compare(T x, T y) where T : class { return x == y; }
It's because if T could be a value type, there could be cases where x == y
would be ill formed - in cases when a type doesn't have an operator == defined. 这是因为如果T可以是值类型,则在某些情况下x == y
可能会格式错误-在类型中未定义运算符==的情况下。 The same will happen for this which is more obvious: 同样的事情也会发生,这更加明显:
void CallFoo(T x) { x.foo(); }
That fails too, because you could pass a type T that wouldn't have a function foo. 那也失败了,因为您可以传递没有函数foo的类型T。 C# forces you to make sure all possible types always have a function foo. C#强制您确保所有可能的类型始终具有函数foo。 That's done by the where clause. 这是通过where子句完成的。
bool Compare(T x, T y) where T : class { return x == y; }
The above will work because == is taken care of in case of user-defined reference types. 上面的方法将起作用,因为在用户定义的引用类型的情况下==会得到照顾。
In case of value types, == can be overridden. 对于值类型,==可以被覆盖。 In which case, "!=" should also be defined. 在这种情况下,也应定义“!=“。
I think that could be the reason, it disallows generic comparison using "==". 我认为这可能是原因,它不允许使用“ ==”进行一般比较。
"...by default == behaves as described above for both predefined and user-defined reference types." “ ...默认情况下,==对于预定义和用户定义的引用类型,其行为均如上所述。”
Type T is not necessarily a reference type, so the compiler can't make that assumption. 类型T不一定是引用类型,因此编译器无法做出该假设。
However, this will compile because it is more explicit: 但是,这将编译,因为它更加明确:
bool Compare(T x, T y) where T : class
{
return x == y;
}
Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?" 跟进另一个问题,“但是,如果我使用的是引用类型,==运算符会使用预定义的引用比较,还是如果一个类型定义了一个,则它会使用运算符的重载版本?”
I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. 我本以为泛型中的==会使用重载版本,但以下测试则相反。 Interesting... I'd love to know why! 有趣的...我很想知道为什么! If someone knows please share. 如果有人知道,请分享。
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare(a, b);
}
static bool Compare(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
Output 输出量
Inline: Overloaded == called 内联:重载==已调用
Generic: 通用:
Press any key to continue . 按任意键继续 。 . 。 . 。
Follow Up 2 跟进2
I do want to point out that changing my compare method to 我确实要指出,将我的比较方法更改为
static bool Compare(T x, T y) where T : Test
{
return x == y;
}
causes the overloaded == operator to be called. 导致重载的==运算符被调用。 I guess without specifying the type (as a where ), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type. 我想如果不指定类型(如where ),编译器就无法推断它应该使用重载运算符...尽管我认为即使不指定类型,编译器也将具有足够的信息来做出该决定。