此问题的解决方法是什么?
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);
}
}
答案 0 :(得分:8)
未使用==
运算符,因为您的通用方法的存在与您将用于T
的类型无关。它无法知道用作T
的所有类型都会使==
运算符超载...您可以使用Equals
方法代替:
private static bool Check<T>(T a, T b) where T : class
{
return Equals(a, b);
}
答案 1 :(得分:4)
这里的“解决方案”是打电话
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
}
答案 2 :(得分:3)
这是一种已知的行为。 MSDN说:
应用
where T : class
约束时,建议使用此约束 你不要在type参数上使用==和!=运算符,因为 这些运算符仅测试参考标识,而不是值相等。即使这些运算符过载也是如此 用作参数的类型。
要检查相等性,您必须实现IEqualityComparer(或直接调用其中一个Equal方法)。
答案 3 :(得分:2)
解决方法是调用虚拟Equals方法,并覆盖:
private static bool Check<T>(T a, T b) where T : class
{
return a.Equals(b);
}
重载的==
运算符在编译时解析,因此它被解析为运算符的System.Object实现。在运行时调度虚拟方法调用,因此将调用System.Object.Equals(如果有)的覆盖。
在您的代码中,虚拟Equals调用发生在重载的==
方法中,该方法未被调用;这就是为什么不调用Equals覆盖的原因。
另一个解决方案,如果你控制传递给方法的类,将限制为IEquatable<T>
,并在你的类中实现它:
private static bool Check<T>(T a, T b) where T : class, IEquatable<T>
{
return a.Equals(b);
}
这将导致重载解析为Equals(T)
方法,这将在运行时保存一些类型检查。