为什么使用generics的“等于”方法解析与显式调用不同
我有以下示例:
namespace ComparisonExample { class Program { static void Main(string[] args) { var hello1 = new Hello(); var hello2 = new Hello(); // calls Hello.Equals var compareExplicitly = hello1.Equals(hello2); // calls Object.Equals var compareWithGenerics = ObjectsEqual(hello1, hello2); } private static bool ObjectsEqual(TValue value1, TValue value2) { return value1.Equals(value2); } } class Hello : IEquatable { public bool Equals(Hello other) { return true; // doesn't matter } } }
问题是为什么在第二个“Equals”调用中,我被重定向到Object.Equals而不是Hello.Equals,即使我在generics参数中指定了确切的类型?
因为您没有告诉generics方法您的对象实现了IEquatable
:
立即尝试:
private static bool ObjectsEqual(TValue value1, TValue value2) where TValue : IEquatable // IMPORTANT!!! { return value1.Equals(value2); }
在您的ObjectsEqual
方法中,您只能访问在object
类中定义的TValue
方法/属性/字段以及在约束中定义的接口/基类中定义的方法。 没有约束=>你只能访问Equals(object)
, GetHashCode()
, GetType()
,(如果你有约束class
: operator==
, operator!=
。)这两个是虚拟的( Equals(object)
, GetHashCode()
),因此您将使用“正确”版本,第三个通常不会被覆盖( GetType()
),因此您可能会使用“正确”版本。 只有两个运算符==
/ !=
经常被覆盖而且看得出来! 在您的通用方法中,您不能使用两者的“正确”版本! 🙂
来自MSDN的补充 :
无界类型参数。
没有约束的类型参数(例如public class SampleClass
称为无界类型参数 。
无界类型参数具有以下规则:
- 无法使用
!=
和==
运算符,因为无法保证具体类型参数将支持这些运算符。 - 它们可以转换为
System.Object
或从System.Object
转换为显式转换为任何接口类型。 - 你可以比较为
null
。 如果将无界参数与null
进行比较,则如果type参数是值类型,则比较将始终返回false
。
在这种情况下, TValue
将转换为System.Object
和Equals
方法。