根据MSDN中==操作符的文档,

For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings. User-defined value types can overload the == operator (see operator). So can user-defined reference types, although by default == behaves as described above for both predefined and user-defined reference types.

那么为什么这个代码片段编译失败呢?

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

当前回答

一般情况下,EqualityComparer<T>. default。对于任何实现了IEquatable<T>或具有合理的Equals实现的东西,Equals都应该完成这项工作。

然而,如果==和=因为某种原因实现不同,那么我在泛型操作符方面的工作应该是有用的;它支持以下操作符版本:

等于(tvalue1, tvalue2) notqual (T value1, T value2) GreaterThan(T value1, T value2) 小于(T value1, T value2) GreaterThanOrEqual(tvalue1, tvalue2) LessThanOrEqual(T value1, T value2)

其他回答

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

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

在我的例子中,我想对等式运算符进行单元测试。我需要在不显式设置泛型类型的情况下调用相等操作符下的代码。建议对EqualityComparer没有帮助,因为EqualityComparer调用Equals方法,而不是相等操作符。

以下是我如何通过构建LINQ来使用泛型类型。它调用==和!=操作符的正确代码:

/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
    // declare the parameters
    var paramA = Expression.Parameter(typeof(T), nameof(a));
    var paramB = Expression.Parameter(typeof(T), nameof(b));
    // get equality expression for the parameters
    var body = Expression.Equal(paramA, paramB);
    // compile it
    var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
    // call it
    return invokeEqualityOperator(a, b);
}

/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
    // declare the parameters
    var paramA = Expression.Parameter(typeof(T), nameof(a));
    var paramB = Expression.Parameter(typeof(T), nameof(b));
    // get equality expression for the parameters
    var body = Expression.NotEqual(paramA, paramB);
    // compile it
    var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
    // call it
    return invokeInequalityOperator(a, b);
}

. equals()适合我,而TKey是一个泛型类型。

public virtual TOutputDto GetOne(TKey id)
{
    var entity =
        _unitOfWork.BaseRepository
            .FindByCondition(x => 
                !x.IsDelete && 
                x.Id.Equals(id))
            .SingleOrDefault();


    // ...
}

bool Compare(T x, T y) where T : class { return x == y; }

上面的代码可以工作,因为在用户定义的引用类型中==已经被处理了。 对于值类型,==可以被重写。在这种情况下,“!="也应该被定义。

我认为这可能是原因,它不允许使用“==”进行一般比较。

如果没有类约束:

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

应该意识到,虽然==操作符中的类约束Equals继承自Object。Equals,而结构的值会覆盖ValueType.Equals。

注意:

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

也给出了相同的编译器错误。

到目前为止,我不明白为什么有一个值类型相等操作符比较被编译器拒绝。但我确实知道,这是可行的:

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