为什么泛型的“等于”方法解析与显式调用不同

本文关键字:调用 泛型 等于 方法 为什么 | 更新日期: 2023-09-27 18:30:35

我有以下示例:

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<Hello>(hello1, hello2); 
        }
        private static bool ObjectsEqual<TValue>(TValue value1, TValue value2)
        {
            return value1.Equals(value2);
        }
    }
    class Hello : IEquatable<Hello>
    {
        public bool Equals(Hello other)
        {
            return true; // doesn't matter
        }
    }
}

问题是为什么在第二个"等于"调用中,即使我在泛型参数中指定了确切的类型,我也会被重定向到 Object.Equals 而不是 Hello.Equals?

为什么泛型的“等于”方法解析与显式调用不同

因为你还没有告诉泛型方法你的对象实现IEquatable<T>

立即试用:

private static bool ObjectsEqual<TValue>(TValue value1, TValue value2) 
               where TValue : IEquatable<TValue> // IMPORTANT!!!
{
    return value1.Equals(value2);
}

ObjectsEqual 方法中,您只能访问在 object 类中定义的方法/属性/TValue字段,以及在约束中定义的接口/基类中定义的方法。没有约束 =>您只能访问Equals(object)GetHashCode()GetType()、(如果您有约束classoperator==operator!=。其中两个是虚拟的(Equals(object)GetHashCode()),所以你会使用"正确"的版本,第三个通常不会被覆盖(GetType()),所以你可能会使用"正确"的版本。只有两个运算符==/!=经常被覆盖,瞧!在您的通用方法中,您不能使用两者的"正确"版本!:-)

来自 MSDN 的添加

无界类型参数。
没有约束的类型参数(如public class SampleClass<T> { }中的T)称为无界类型参数
无界类型参数具有以下规则:

  • 不能使用 !=== 运算符,因为无法保证具体类型参数将支持这些运算符。
  • 它们可以与System.Object相互转换,也可以显式转换为任何接口类型。
  • 您可以与null进行比较.如果将无界参数与null进行比较,则比较将始终返回false如果类型参数是值类型。

在这种情况下,TValue将转换为System.Object并调用Equals方法。