根据MSDN中==操作符的文档,

For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. 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.

那么为什么这个代码片段编译失败呢?

bool Compare<T>(T x, T y) { return x == y; }

我得到错误操作符'=='不能应用于类型为'T'和'T'的操作数。我想知道为什么,因为据我所知==操作符是预定义的所有类型?

编辑:谢谢大家。一开始我并没有注意到这个语句只是关于引用类型的。我还认为为所有值类型提供了逐位比较,现在我知道这是不正确的。

但是,如果我使用引用类型,==操作符是否会使用预定义的引用比较,或者如果类型定义了引用比较,它是否会使用操作符的重载版本?

编辑2:通过反复试验,我们了解到==操作符在使用不受限制的泛型类型时将使用预定义的引用比较。实际上,编译器将使用它可以为受限类型参数找到的最佳方法,但不会再寻找其他方法。例如,下面的代码将始终打印true,即使当Test。test<B>(new B(), new B())调用:

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>(T a, T b) where T : A { Console.WriteLine(a == b); } }

当前回答

如果你想确保你的自定义类型的操作符被调用,你可以通过反射来实现。只需使用您的泛型参数获取类型,并为所需的操作符检索MethodInfo(例如op_Equality, op_Inequality, op_LessThan…)

var methodInfo = typeof (T).GetMethod("op_Equality", 
                             BindingFlags.Static | BindingFlags.Public);    

然后使用MethodInfo的Invoke方法执行操作符,并将对象作为参数传入。

var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});

这将调用重载操作符,而不是应用在泛型参数上的约束所定义的操作符。可能不实用,但在使用包含几个测试的泛型基类时,可以方便地对操作符进行单元测试。

其他回答

这么多答案,却没有一个能解释为什么?(乔瓦尼明确问了这个问题)……

. net泛型不像c++模板。在c++模板中,重载解析发生在实际模板参数已知之后。

在. net泛型(包括c#)中,在不知道实际泛型参数的情况下就会发生重载解析。编译器用于选择要调用的函数的唯一信息来自泛型参数上的类型约束。

这里有一个MSDN Connect条目

Alex Turner的回答是这样开始的:

不幸的是,这种行为是由 设计并不是一件容易的事 使用==类型的解决方案 可能包含value的参数 类型。

一般情况下,EqualityComparer<T>. default。对于任何实现了IEquatable<T>或具有合理的Equals实现的东西,Equals都应该完成这项工作。

然而,如果==和=因为某种原因实现不同,那么我在泛型操作符方面的工作应该是有用的;它支持以下操作符版本:

等于(tvalue1, tvalue2) notqual (T value1, T value2) GreaterThan(T value1, T value2) 小于(T value1, T value2) GreaterThanOrEqual(tvalue1, tvalue2) LessThanOrEqual(T value1, T value2)

我有两个解,它们很简单。

解决方案1:将泛型类型变量强制转换为object并使用==运算符。

例子:

void Foo<T>(T t1, T t2)
{
   object o1 = t1;
   object o2 = t2;
   if (o1 == o2)
   {
      // ...
      // ..
      // . 
   }
}

解决方案2:使用object。Equals(object, object)方法。

例子:

void Foo<T>(T t1, T t2)
{
   if (object.Equals(t1, t2)
   {
       // ...
       // ..
       // .
   }
}

正如其他人所说,只有当T被约束为引用类型时,它才会工作。在没有任何约束的情况下,您可以与null进行比较,但只能与null进行比较——对于非空值类型,这种比较将始终为假。

与其调用Equals,不如使用IComparer<T> -如果没有更多信息,则使用EqualityComparer<T>。默认是一个不错的选择:

public bool Compare<T>(T x, T y)
{
    return EqualityComparer<T>.Default.Equals(x, y);
}

除此之外,这避免了装箱/类型转换。