泛型函数参数的多态行为:为何调用FirstChild的Fun而非SecondChild?
为什么
Test(child)调用的是FirstChild.Fun而不是SecondChild.Fun? 这事儿的核心在于两个关键点:new关键字的隐藏特性和泛型方法中虚拟方法的绑定逻辑,咱们一步步拆解:
1. new关键字是「隐藏」方法,不是「重写」
你在SecondChild里写的public new void Fun(),本质是隐藏了从FirstChild继承来的Fun方法,而不是重写它。这意味着:
- 这个
SecondChild.Fun是一个全新的方法,和父类的Fun没有多态关联; - 只有当你直接用
SecondChild类型的变量调用Fun时,才会执行这个新方法; - 如果是通过父类(
Parent或FirstChild)的引用调用Fun,CLR会完全忽略这个隐藏的方法,走原本的多态override链。
2. 泛型方法Test<T>的方法绑定逻辑
泛型方法Test<T>的约束是where T : Parent,所以编译器在处理entity.Fun()的时候,会基于Parent类的方法定义来做绑定——因为Parent.Fun是virtual的,所以这是一个虚拟调用(virtual call),而不是绑定到T类型的new方法。
当你调用Test(child)时,T被推断为SecondChild,但运行时的虚拟调用逻辑是这样的:
- CLR找到对象的实际类型(
SecondChild); - 检查这个类型是否重写了
Parent.Fun——但SecondChild的Fun是用new定义的,没有重写父类的virtual方法; - 于是往上找父类
FirstChild,发现它重写了Parent.Fun,所以执行FirstChild.Fun的实现。
要是你直接写child.Fun(),就会输出In SecondChild,因为这是直接调用SecondChild的隐藏方法,不走虚拟调用链。
3. 有没有强制转换?
完全没有。泛型方法里的entity就是SecondChild类型,没有任何显式或隐式的类型转换。虚拟调用本身就是CLR通过对象的方法表动态查找正确实现的过程,和类型转换无关。
举个更直观的对比验证:
SecondChild child = new SecondChild(); child.Fun(); // 输出"In SecondChild" Parent p = child; p.Fun(); // 输出"In FirstChild"——和泛型方法的结果一致
内容的提问来源于stack exchange,提问作者Henry159
相关产品推荐
相关产品推荐

