.Net 填坑 接口、父类、子类同名方法的调用
先看代码
1.类与接口定义
class B : IDisposable, Test{public void Dispose(){Console.WriteLine("B Dispose");}public virtual void Test(){Console.WriteLine("B Test");}}interface Test{void Test();}class C : B, Test{public new void Test(){Console.WriteLine("C Test");}}
2.调用方法
static void Main(string[] args){Test c = new C();c.Test();c = new B();c.Test();B b = new C();b.Test();Console.ReadLine();}
输出如下:
C Test
B Test
B Test
1.其中第一输出,表示用接口类变量来调用方法时,(类似虚方法调用),会找到变量对应的实际实例(此例子中是类型C的实例对象c),找到实例的类型对象(C类型)的Test方法。
2.第二个输出,同一个原则,实际类型是B类型,所以输出B
3.按照虚方法定义,也应该找到对应实际类型的Test方法来输出,但是输出的是B。原因在于C方法中的New关键字,表示是C类型独有的新的方法,而不是真正的C中的重写父类B中的方法,所以流程是:先找到C类型对象,查找虚方法Test,结果是没找到,然后再去B类中找,找到了,调用B类中的方法。
对应的I代码:
IL_0007: ldloc.0 // cIL_0008: callvirt instance void Program/Test::Test()IL_000d: nopIL_0014: ldloc.0 // cIL_0015: callvirt instance void Program/Test::Test()IL_001a: nopIL_0021: ldloc.1 // bIL_0022: callvirt instance void Program/B::Test()IL_0027: nop
可以看到,接口变量调用方法也是虚方法调用的方式
1.将C中的New 改为override后
结果:
C Test
B Test
C Test
第3个流程发生变化,此时C中Test认为是复写了父类B中的虚方法,所以按虚方法的流程,找到实际对象中C的方法进行了调用。
2.去掉C中继承的Test接口
class C : B{public override void Test(){Console.WriteLine("C Test");}}
打印结果:与上面相同,都是走的虚方法调用
3.去掉C中的Test接口,同时修改C中方法为New
class C : B{public new void Test(){Console.WriteLine("C Test");}}
结果:
B Test
B Test
B Test
此时C中的Test方法,认为是新的只属于C的方法。
1.第一个变为打印B,因为接口走的虚方法调用的原理,去找实际类型C中有没有覆盖的Test方法,没找到(因为New关键字表示C独有的新的方法),然后找到父类B中的虚方法去调用。
2.第2个,找到实例对象B的虚方法,找到了,直接调用
3.第3个,还是B,因为用虚方法调用,去找C中的复写Test虚方法,没找到,从而去找父类B中的,流程与1相同
总结
方法调用,要看调用方法的方式,实例方法与虚方法。
实例方法,直接按变量类型,去找到对应的方法直接调用
实例虚方法,找到变量实际的存储类型,去一层层找到有无复写的虚方法
注意:new与override关键字的区别,特别是new关键字,可以当做是独立的属于类型自身的方法。