在通用函数中使用重载的operator==

12

请看以下代码:

class CustomClass
{
    public CustomClass(string value)
        { m_value = value; }

    public static bool operator ==(CustomClass a, CustomClass b)
        { return a.m_value == b.m_value; }

    public static bool operator !=(CustomClass a, CustomClass b)
        { return a.m_value != b.m_value; }

    public override bool Equals(object o)
        { return m_value == (o as CustomClass).m_value; }

    public override int GetHashCode()
        { return 0; /* not needed */ }

    string m_value;
}

class G
{
    public static bool enericFunction1<T>(T a1, T a2) where T : class
        { return a1.Equals(a2); }
    public static bool enericFunction2<T>(T a1, T a2) where T : class
        { return a1==a2; }
}

现在当我调用这两个通用函数时,一个成功一个失败:
var a = new CustomClass("same value");
var b = new CustomClass("same value");
Debug.Assert(G.enericFunction1(a, b)); // Succeeds
Debug.Assert(G.enericFunction2(a, b)); // Fails

显然,G.enericFunction2执行了默认的operator==实现而不是我的重载。有人能解释一下为什么会发生这种情况吗?

a1.Equals(a2)调用一个虚拟实例方法。即使重载在编译时被固定为System.Object.Equals(System.Object),在运行时总是调用被覆盖的方法。这就是虚拟方法的全部意义。说a1 == a2调用一个静态方法(至少形式上存在一个方法public static bool operator ==(object x, object y) { ... })。==的重载在编译时被固定,由于T没有被限制为与您的自定义==匹配的内容,因此编译器唯一可以选择的是object版本的== - Jeppe Stig Nielsen
2个回答

14

来自类型参数的限制(C#编程指南):

应用where T:class约束时,避免在类型参数上使用==和!=运算符,因为这些运算符仅测试引用标识,而不是值相等性。即使这些运算符在作为参数使用的类型中进行了重载,也是如此。(...) 这种行为之所以发生是因为在编译时,编译器只知道T是引用类型,因此必须使用适用于所有引用类型的默认运算符。


0
如果我将enericFunction2更改为:
    public static bool enericFunction2<T>(T a1, T a2) where T : class
    {
        object aa = a1;
        CustomClass obj1 = (CustomClass)aa;

        object bb = a2;
        CustomClass obj2 = (CustomClass)bb;

        return obj1 == obj2; 
    }

然后一切都正常工作。但我担心我无法解释它。我的意思是a1a2知道它们的类型。为什么需要将CustomClass强制转换,以便调用运算符?


谢谢,但我想使用一个通用类型而不是固定类型CustomClass。 - Dimitri C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接