2010-08-12 63 views
2

这里是我的简单的代码:为什么两个泛型不能与'=='比较?

T a; 
T b; 

if (a == b) 
// sth. 
else 
// sth. else 

当我尝试编译,我得到一个错误说的==操作是泛型类型无效。所以我必须使用object.Equals()方法。

是不是==操作员实际上调用objectEquals方法?为什么我可以使用两种通用类型的Equals方法,但不使用==运算符?

+1

我刚刚检查,代码示例似乎编译(添加样板和大括号后)。你能展示一个更全面的代码示例吗? – strager 2010-08-12 02:11:54

+7

David,你问了10个问题并接受了0个答案。你知道如何将正确答案标记为已接受吗? – 2010-08-12 02:13:12

+0

Nevermind ...似乎编译器正在优化掉不必要的'a == b'比较,因为它们都被设置为'null'(或者某些;不完全确定)。 – strager 2010-08-12 02:26:08

回答

8

operator ==必须结构被重载以被使用,因此完全不受约束类型参数不能使用它。您可以约束功能class允许默认的基准进行比较:

public void Foo<T>() where T : class { 
     T a = default(T); 
     T b = a; 

     if(a == b) 
      System.Diagnostics.Debug.WriteLine(""); 
     else 
      System.Diagnostics.Debug.WriteLine(""); 
    } 

上面的代码工作,因为在默认情况下,引用类型可以用operator ==使用:

对于引用类型字符串以外, ==如果其两个操作数引用同一个对象,则返回true。

这就是为什么if (new object() == new object()) {}编译,即使System.Object不超载operator ==

2

==运算符没有定义的T的所有可能值[感谢丹尼尔](或可能已放置于T的任何约束,我假设),所以可以不使用它。您只能拨打运营商的方法,可以由T.代表的所有可能的类型

==操作符调用在许多情况下,“等于”被调用,但这并不意味着对T的属性他们是同样的事情。

+2

实际上,运算符== *是*在对象上定义的,而不是在结构体上。对于大多数参考类型,==不调用.Equals。前者通常实现身份比较(不可变类型除外),后者通常实现价值比较。 – 2010-08-12 02:48:48

+0

使用ndepend进行的一项快速调查显示,BCL中的大多数引用类型不定义运算符== - 为它们提供ReferenceEquals而不是值比较行为。 有趣的是,运算符==实际上并没有在'object'上定义,只要我能看到 - 相反,我相信c#(或其他语言)编译器最终编译为'.ceq',对于引用类型参考平等风格检查。 – 2010-08-12 03:49:13

+0

我不''在'object'上定义。相反,当不存在对'=='的重载时,编译器本身会尝试将它解释为给定的特定类型的引用比较运算符,并查看是否有意义。运算符重载并不关心传入的操作数是密封的还是非密封的,但是C#引用相等检查运算符(引用的非密封类类型可以与其未实现的接口之一进行比较,而是引用到密封的班级不能)。 – supercat 2013-12-19 17:27:40

1

==令牌用于表示在C#的两个不同的运营商。只有当操作数的类型符合“相等检查”操作符的特定定义的重载时,它们才适用。第二个测试引用相等,只适用于一个操作数是null,一个操作数是类类型,另一个是该类型的实例可以实现的接口,它们都是接口,都是相同的类类型,或者都是类类型一个是另一个的超类型。第一种形式在泛型上不可用,除非泛型被限制为定义了等式检查过载的类型;第二种形式限于已知满足特定条件的参考类型。请注意,在某些情况下,第二个操作员可以在第一个操作员想要的地方使用,例如, bool IsSame<T>(T p1, T p2) where T:class { return p1==p2; }将通过使用参考比较来比较String类型的两个变量,即使为String定义了==的过载。这是因为T不是公知足够适用的==String一个过载,但==两个操作数是已知的相同的引用类型。

这可能是值得注意的是,一些其它语言使用不同的令牌的两种操作C#进行使用==。例如,VB.NET使用=进行相等比较,Is用于参考相等。