为何C#泛型函数MyFunc未调用MyClass的自定义Equals方法?
为什么泛型方法未触发自定义的Equals重载?
代码场景
MyClass 定义
public class MyClass { int MyProp { get; set; } public MyClass(int val) { MyProp = val; } public bool Equals(MyClass obj) { return MyProp == obj.MyProp; } }
泛型函数定义
bool MyFunc<T>(T obj1, T obj2) { return obj1.Equals(obj2); }
调用代码
MyFunc(new MyClass(1), new MyClass(2))
核心原因
泛型方法MyFunc<T>里的T没有任何约束,编译时编译器只能将obj1视为object类型(所有C#类型的基类)。此时调用的Equals是object.Equals(object),而非你在MyClass中定义的Equals(MyClass)重载。
虽然运行时T被推断为MyClass,但泛型方法的方法绑定是编译时静态绑定的——编译器不会因为运行时的具体类型,改变编译阶段选定的方法版本。你的Equals(MyClass)只是重载,没有重写object.Equals(object),所以通过object引用调用时,只会触发基类的默认引用相等比较逻辑,不会走到你的自定义方法里。
修复方案
方案1:重写基类Equals并实现IEquatable(推荐)
这是C#中实现自定义相等逻辑的标准做法,既保证兼容性,又能避免不必要的装箱操作:
public class MyClass : IEquatable<MyClass> { int MyProp { get; set; } public MyClass(int val) { MyProp = val; } // 重写object.Equals(object),统一相等判断入口 public override bool Equals(object obj) { return Equals(obj as MyClass); } // 实现IEquatable<MyClass>的强类型Equals,避免装箱开销 public bool Equals(MyClass obj) { if (obj is null) return false; return MyProp == obj.MyProp; } // 重写GetHashCode是重写Equals的强制规范,避免哈希表类容器出错 public override int GetHashCode() { return MyProp.GetHashCode(); } }
修改后,无论通过object还是MyClass类型调用Equals,都会触发你的自定义相等逻辑,泛型方法里的调用自然也能正常工作。
方案2:给泛型方法添加类型约束
如果不想修改MyClass,可以给MyFunc<T>添加where T : MyClass约束,让编译器明确知道T是MyClass或其子类,从而直接绑定到MyClass.Equals(MyClass):
bool MyFunc<T>(T obj1, T obj2) where T : MyClass { return obj1.Equals(obj2); }
但这种方式局限性强,仅适用于MyClass及其子类场景,通用性远不如方案1。
内容的提问来源于stack exchange,提问作者Harry Stuart
相关产品推荐
相关产品推荐

