在相等运算符实现中引用相等运算符

时间:2011-08-07 17:30:15

标签: c# .net

使用Reflector或DotPeek,等于运算符重载的System.Linq.Data.Binary实现如下所示:

[Serializable, DataContract]
public sealed class Binary : IEquatable<Binary>
{
...
    public static bool operator ==(Binary binary1, Binary binary2)
    {
        return ((binary1 == binary2) || (((binary1 == null) && (binary2 == null)) || (((binary1 != null) && (binary2 != null)) && binary1.EqualsTo(binary2))));
    }

我必须遗漏一些明显的东西,或者有一种我不知道的机制(比如在体内隐式调用object ==?)。我承认,我很少需要重载标准运算符。

为什么这个实现不会导致无限递归(一个简单的测试表明它不会无限递归)?第一个条件表达式是binary1 == binary2,在运算符重载的实现中,如果你在实现之外使用了binary1 == binary2,那么它会被调用,我也会在内部思考。

2 个答案:

答案 0 :(得分:5)

我希望这是你的反编译器中的一个错误。 Redgate Reflector有/同样的错误,我也found it in ILSpy

这很难反编译的原因是因为它巧妙地测试了C#重载规则。原始代码很可能类似(object)obj1==(object)obj2,但在IL本身中无法看到此转换。就运行时而言,将任何引用类型转换为基类型都是无操作。但它确实让C#选择引用等式操作码,而不是调用重载的相等操作符。

IMO在反编译器中实现这一点的正确方法是始终将引用相等性检查反编译为(object)obj1==(object)obj2,然后在不影响重载决策的情况下优化冗余转换。这种方法也可以解决方法重载的类似问题。

答案 1 :(得分:2)

显然,你的ReSharper(和dotpeek)版本中存在一个错误。 ReSharper版本6.0(6.0.2202.688)正确执行:

    public static bool operator ==(Binary binary1, Binary binary2) {
        if ((object)binary1 == (object)binary2) 
            return true; 
        if ((object)binary1 == null && (object)binary2 == null)
            return true; 
        if ((object)binary1 == null || (object)binary2 == null)
            return false;
        return binary1.EqualsTo(binary2);
    }