为什么通用函数中的代码忽略了重载的==运算符

时间:2012-03-21 15:49:12

标签: c#

此问题的解决方法是什么?

class Program
{
    static void Main(string[] args)
    {
        var a = new Test();
        var b = new Test();
        var eq = Check(a, b);
    }

    private static bool Check<T>(T a, T b) where T : class
    {
        return a == b; //will not call overloaded == 
    }
}
public class Test
{
    public override bool Equals(object obj)
    {
        Test other = obj as Test;
        if (ReferenceEquals(other, null)) return false;
        return true;
    }
    public static bool operator ==(Test left, Test right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(Test left, Test right)
    {
        return !(left == right);
    }
}

4 个答案:

答案 0 :(得分:8)

未使用==运算符,因为您的通用方法的存在与您将用于T的类型无关。它无法知道用作T的所有类型都会使==运算符超载...您可以使用Equals方法代替:

private static bool Check<T>(T a, T b) where T : class
{
    return Equals(a, b);
}

答案 1 :(得分:4)

这里的“解决方案”是打电话

 private static bool Check<T>(T a, T b) where T : class
 {
     //return a == b;      // will not call overloaded == 
     return a.Equals(b);   // will cal overloaded Equals
 }

答案 2 :(得分:3)

这是一种已知的行为。 MSDN说:

  

应用where T : class约束时,建议使用此约束   你不要在type参数上使用==和!=运算符,因为   这些运算符仅测试参考标识,而不是值相等。即使这些运算符过载也是如此   用作参数的类型。

要检查相等性,您必须实现IEqualityComparer(或直接调用其中一个Equal方法)。

答案 3 :(得分:2)

解决方法是调用虚拟Equals方法,并覆盖:

private static bool Check<T>(T a, T b) where T : class 
{ 
    return a.Equals(b);
} 

重载的==运算符在编译时解析,因此它被解析为运算符的System.Object实现。在运行时调度虚拟方法调用,因此将调用System.Object.Equals(如果有)的覆盖。

在您的代码中,虚拟Equals调用发生在重载的==方法中,该方法未被调用;这就是为什么不调用Equals覆盖的原因。

另一个解决方案,如果你控制传递给方法的类,将限制为IEquatable<T>,并在你的类中实现它:

private static bool Check<T>(T a, T b) where T : class, IEquatable<T>
{ 
    return a.Equals(b);
}

这将导致重载解析为Equals(T)方法,这将在运行时保存一些类型检查。