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

根据MSDN中==运算符的文档,

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

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

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

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

编辑:谢谢大家。 起初我没有注意到这个陈述只是关于参考类型。 我还认为,所有值类型都提供了逐位比较,现在我知道这是不正确的。

但是,如果我使用引用类型,那么==运算符会使用预定义的引用比较,还是使用运算符的重载版本(如果类型定义了一个)?

编辑2:通过试验和错误,我们了解到,当使用不受限制的泛型类型时, ==运算符将使用预定义的引用比较。 实际上,编译器会使用它可以找到的限制类型参数的最佳方法,但不会再看到。 例如,即使在Test.test<B>(new B(), new B())时,下面的代码将始终显示为true

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

“...默认情况下==对于预定义和用户定义的引用类型都如上所述。”

类型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),编译器不能推断它应该使用重载操作符......尽管我认为即使没有指定类型,它也会有足够的信息来作出该决定。


正如其他人所说,只有当T被限制为参考类型时,它才会起作用。 如果没有任何约束,可以将其与null进行比较,但只能为null - 并且对于不可为空的值类型,该比较始终为false。

不用调用Equals,最好使用IComparer<T> - 如果没有更多信息, EqualityComparer<T>.Default是一个不错的选择:

public bool Compare<T>(T x, T y)
{
    return EqualityComparer<T>.Default.Equals(x, y);
}

除了别的之外,这可以避免拳击/投射。


一般来说, EqualityComparer<T>.Default.Equals应该使用实现IEquatable<T>任何东西,或者有一个明智的Equals实现。

但是,如果==Equals由于某种原因而实现不同,那么我对泛型操作符的工作应该是有用的; 它支持(除其他外)的操作员版本:

  • 相等(T值1,T值2)
  • NotEqual(T值1,T值2)
  • GreaterThan(T值1,T值2)
  • LessThan(T值1,T值2)
  • GreaterThanOrEqual(T值1,T值2)
  • LessThanOrEqual(T值1,T值2)
  • 链接地址: http://www.djcxy.com/p/10041.html

    上一篇: Can't operator == be applied to generic types in C#?

    下一篇: "is" operator behaves unexpectedly with integers