不能将运算符==应用于C#中的泛型类型?
根据MSDN中==
运算符的文档,
对于预定义的值类型,如果操作数的值相等,则相等运算符(==)返回true,否则返回false。 对于字符串以外的引用类型,如果其两个操作数引用同一对象,则==会返回true。 对于字符串类型,==比较字符串的值。 用户定义的值类型可以重载==运算符(请参阅运算符)。 因此,用户定义的引用类型,尽管默认情况下==对于预定义和用户定义的引用类型的行为如上所述。
那么为什么这段代码片段无法编译?
void Compare<T>(T x, T y) { return x == y; }
我得到错误操作符'=='不能应用于'T'和'T'类型的操作数。 我想知道为什么,因为据我所知, ==
运算符是为所有类型预定义的?
编辑:谢谢大家。 起初我没有注意到这个陈述只是关于参考类型。 我还认为,所有值类型都提供了逐位比较,现在我知道这是不正确的。
但是,如果我使用引用类型,那么==
运算符会使用预定义的引用比较,还是使用运算符的重载版本(如果类型定义了一个)?
编辑2:通过试验和错误,我们了解到,当使用不受限制的泛型类型时, ==
运算符将使用预定义的引用比较。 实际上,编译器会使用它可以找到的限制类型参数的最佳方法,但不会再看到。 例如,即使在Test.test<B>(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>(T a, T b) where T : A { Console.WriteLine(a == b); } }
“...默认情况下==对于预定义和用户定义的引用类型都如上所述。”
类型T不一定是引用类型,所以编译器不能做出这样的假设。
但是,这会被编译,因为它更明确:
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
后续附加问题,“但是,如果我使用的是引用类型,那么==运算符会使用预定义的引用比较,还是使用运算符的重载版本(如果类型定义了一个)?
我原以为==上的泛型会使用重载版本,但下面的测试说明了其他情况。 有趣...我想知道为什么! 如果有人知道请分享。
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<Test>(a, b);
}
static bool Compare<T>(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);
}
}
}
产量
内联:重载==调用
通用:
按任意键继续 。 。 。
跟进2
我想指出,改变我的比较方法
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
导致重载的==运算符被调用。 我猜没有指定类型(作为where),编译器不能推断它应该使用重载操作符......尽管我认为即使没有指定类型,它也会有足够的信息来作出该决定。
正如其他人所说,只有当T被限制为参考类型时,它才会起作用。 如果没有任何约束,可以将其与null进行比较,但只能为null - 并且对于不可为空的值类型,该比较始终为false。
不用调用Equals,最好使用IComparer<T>
- 如果没有更多信息, EqualityComparer<T>.Default
是一个不错的选择:
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
除了别的之外,这可以避免拳击/投射。
一般来说, EqualityComparer<T>.Default.Equals
应该使用实现IEquatable<T>
任何东西,或者有一个明智的Equals
实现。
但是,如果==
和Equals
由于某种原因而实现不同,那么我对泛型操作符的工作应该是有用的; 它支持(除其他外)的操作员版本: