Bru*_*uno 4 c# virtual overriding interface new-operator
昨天我发布了一个关于new/virtual/override关键字的问题,我从你的答案中学到了很多东西.但我仍有一些疑虑.
在所有"盒子"之间,我与类型的方法表中真正发生的事情失去联系.例如:
interface I1 { void Draw(); }
interface I2 { void Draw(); }
class A : I1, I2
{
public void Minstance() { Console.WriteLine("A::MInstance"); }
public virtual void Draw() { Console.WriteLine("A::Draw"); }
void I2.Draw() { Console.WriteLine("A::I2.Draw"); }
}
class B : A, I1, I2
{
public new virtual void Draw() { Console.WriteLine("B::Draw"); }
void I1.Draw() { Console.WriteLine("B::I1.Draw"); }
}
class Test
{
public static void Main()
{
A a = new B();
a.Draw();
I1 i1 = new A();
i1.Draw();
I2 i2 = new B();
i2.Draw();
B b = (B)a;
b.Draw();
}
}
}
Run Code Online (Sandbox Code Playgroud)
关于此练习的问题是:根据代码填写类型的方法表,并解释运行Main()生成的输出.
我的回答是:在A型,我们有3种方法:MInstance(),画() - 在A ::画版 - 和I2 ::绘制B型,我们有4种方法:MInstance从A,B ::抽奖,I1 :: Draw和I2 :: Draw
我对自己的答案不太自信,这就是为什么我发布这个问题.当我们实现接口时,它在方法表上为所述接口的方法创建了一个新槽?我们不应该在A类中实现I2 :: Draw吗?
同样地,当我们称使用接口可变的方法(如i1.Draw())我明白我们是在动态调度,因此,我们应该看看对象的类型被保持由变量(A型在这种情况下)并在A的方法表中搜索专门调用I1.Draw的方法.但是,如果我们找不到它呢?我应该如何处理这些案件?为了成功解决这些问题,我应该知道任何经验法则吗?
很抱歉这个问题太无聊了,但我真的需要解开这个问题;)
干杯!
好问题.
考虑这一点的方法是:接口获得自己的一组插槽.需要一个实现接口的类来填充这些插槽.
现在请记住,重载解析的工作是根据类型和参数选择插槽.没有参数,所以编译器只有类型可以去掉.
编译器生成的代码"在运行时调用所选插槽中的任何方法".
加起来:
A a1 = new A();
A a2 = new B();
B b = new B();
(a1 as A).Draw(); // ADrawSLOT contains A::Draw
(a1 as I1).Draw(); // I1SLOT contains A::Draw
(a1 as I2).Draw(); // I2SLOT contains A::I2.Draw
(a2 as A).Draw(); // ADrawSLOT contains A::Draw
(a2 as B).Draw(); // BDrawSLOT contains B::Draw
(a2 as I1).Draw(); // I1SLOT contains B::I1.Draw
(a2 as I2).Draw(); // I2SLOT contains B::Draw
(b as A).Draw(); // ADrawSLOT contains A::Draw
(b as B).Draw(); // BDrawSLOT contains B::Draw
(b as I1).Draw(); // I1SLOT contains B::I1Draw
(b as I2).Draw(); // I2SLOT contains B::Draw
Run Code Online (Sandbox Code Playgroud)
如果您对如何实现它感兴趣,请使用ILDASM反汇编您的程序,然后查看元数据表25(0x19),MethodImpl表.这个程序的MethodImplTable是:
1 == 0:TypeDef[2000004], 1:MethodDefOrRef[06000005], 2:MethodDefOrRef[06000002]
2 == 0:TypeDef[2000005], 1:MethodDefOrRef[06000008], 2:MethodDefOrRef[06000001]
Run Code Online (Sandbox Code Playgroud)
然后你可以查看typedef和methoddef表,你会看到这个解码为:
in type A the method A::I2.Draw implements the method I2::Draw
in type B the method B::I1.Draw implements the method I1::Draw
Run Code Online (Sandbox Code Playgroud)
MethodImpl表是CLI如何表示"我需要在此插槽中粘贴某些内容与常规名称匹配规则选择的内容不同"的概念.通常,名称匹配规则会选择一个名为"Draw"的方法进入该槽,而不是"I1.Draw"或"I2.Draw".
您可能还想阅读CLI规范的第II部分第22.27节.