C# 为什么泛型函数中的代码忽略重载==运算符

C# 为什么泛型函数中的代码忽略重载==运算符,c#,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

这个问题的解决方法是什么

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);
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var a=新测试();
var b=新测试();
var eq=检查(a,b);
}
私有静态布尔检查(TA,TB),其中T:class
{
返回a==b;//将不调用重载==
}
}
公开课考试
{
公共覆盖布尔等于(对象对象对象)
{
测试其他=obj作为测试;
if(ReferenceEquals(other,null))返回false;
返回true;
}
公共静态布尔运算符==(测试左、测试右)
{
返回等于(左、右);
}
公共静态布尔运算符!=(测试左、测试右)
{
返回!(左==右);
}
}

未使用
=
运算符,因为您的泛型方法独立于将用于
T
的类型而存在。它无法知道用作
T
的所有类型都将重载
=
运算符。。。您可以改为使用
Equals
方法:

private static bool Check<T>(T a, T b) where T : class
{
    return Equals(a, b);
}
私有静态布尔检查(ta,tb),其中T:class
{
回报等于(a,b);
}

这里的“解决方案”是调用

 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
 }
私有静态布尔检查(ta,tb),其中T:class
{
//返回a==b;//将不调用重载==
返回a.Equals(b);//将cal重载为Equals
}

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

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

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

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

应用
where T:class
约束时,建议 您不使用==和!=类型参数上的运算符,因为 这些运算符将仅测试引用标识,而不测试值是否相等。即使这些运算符在中重载,情况也是如此 用作参数的类型


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

如果将
==
运算符替换为
ReferenceEquals
,是否有效?@code4life
==
已在执行引用相等性检查;正确的解决方案是使用
Equals
==是重载,而不是重写。当您不约束泛型类型时,它的行为就好像它是用于重载目的的对象一样。也就是说,它采用所有可能的类型T的最小公分母。首先,这是泛型,在编译时知道该类型;其次,为什么它不在编译时检查它runtime@AlexBurtsev泛型类型在编译时未知。C泛型不能像C++模板那样工作。编译它们是为了处理任何可能的类型参数,而不是实际使用的类型参数。@AlexBurtsev第二,运算符不是虚拟的;i、 例如,它们重载而不是重写,这意味着没有虚拟(运行时)调度。编译时在
Main
方法中知道类型,而在
Check
方法中不知道类型。它在运行时不会检查,因为C#是一种静态类型的语言;它不像在动态语言中那样进行后期绑定(除非您使用
dynamic
)+1来提及
IEqualityComparer
,但我认为您的意思是
IEquatable
。您还需要检查a是否为null。。。更容易使用静态Equals方法是的,
a==b
a.Equals(b)
不同,因为如果
a
为空(或者至少不应该),前者不会爆炸。最好使用:
EqualityComparer.Default.Equals(a,b)
a==b
a.Equals(b)
不同,因为如果
a
为空(或者至少不应该为空),前者不会爆炸。最好使用:
EqualityComparer.Default.Equals(a,b)
@nawfal这是真的。我应该在示例代码中包含一个空检查,但是
EqualityComparer.Default.Equals无疑会执行我忘记的所有正确检查,因此调用
Equals
方法是一种更好的方法。当然,如果调用相等比较器并在相等覆盖中执行空检查,则将执行两次。
private static bool Check<T>(T a, T b) where T : class, IEquatable<T>
{ 
    return a.Equals(b);
}