一尘不染

运算符==不能应用于C#中的泛型类型吗?

c#

根据MSDN中==运营商的文档,

对于预定义的值类型,相等运算符(==)如果其操作数的值相等,则返回true,否则返回false。对于字符串以外的引用类型,如果==的两个操作数引用同一对象,则==返回true。对于字符串类型,==比较字符串的值。用户定义的值类型可能会使==运算符重载(请参阅运算符)。用户定义的引用类型也可以,尽管
默认情况下==的行为与上述预定义和用户定义的引用类型相同。

那么,为什么此代码片段无法编译?

bool Compare<T>(T x, T y) { return x == y; }

我收到错误 运算符’==’不能应用于类型’T’和’T’的操作数 。我想知道为什么,因为据我了解,该==操作符是为所有类型预定义的?

编辑: 谢谢大家。起初我没有注意到该声明仅涉及引用类型。我还认为为所有值类型提供了逐位比较,现在我知道这是 正确的。

但是,如果我使用的是引用类型,==操作员会使用预定义的引用比较吗?如果定义了一个类型,操作员会使用重载版本吗?

编辑2:
通过反复试验,我们了解到,==当使用无限制的泛型类型时,运算符将使用预定义的引用比较。实际上,编译器将使用它可以为受限类型参数找到的最佳方法,但是不再赘述。例如,true即使Test.test<B>(new B(), new B())被调用,下面的代码也将始终打印:

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); } }

阅读 537

收藏
2020-05-19

共1个答案

一尘不染

“ …默认情况下,==对于预定义和用户定义的引用类型,其行为均如上所述。”

类型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
),编译器就无法推断它应该使用重载运算符…尽管我认为即使不指定类型,编译器也将具有足够的信息来做出该决定。

2020-05-19