更多关于虚拟/新...加上接口! [英] More about Virtual / new...plus interfaces!

查看:101
本文介绍了更多关于虚拟/新...加上接口!的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我昨天发布了有关新的/虚拟/覆盖关键字的问题,我从你的答案学到了很多东西。但我仍留在有些疑惑。

Yesterday I posted a question about the new/virtual/override keywords, and i learned a lot from your answers. But still i remain with some doubts.

在所有的盒子之间,我失去了联系,什么是真正发生在该类型的方法表。例如:

In between all the "boxes", i lost touch with what's really happening to the type's method tables. For instance:

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();
    }

}
}



问题问及这项工作,多数民众赞成是:根据代码填写类型的方法表,并解释运行中的main()生成的输出

The question thats asked on this exercise is: Fill in the types' method tables according to the code, and explain the output generated by running the Main().

我的回答是:
在A型,我们有3种方法:MInstance(),画() - 在A ::画版 - 和I2 ::抽奖
在b型,我们有4种方法:MInstance从A,b: :画图,I1 :: Draw和I2 ::绘制

My answer was: In type A we have 3 methods: MInstance(), Draw()- the A::Draw version - and I2::Draw In type B we have 4 methods: MInstance from A, B::Draw, I1::Draw and I2::Draw

我不是很自信我的回答,为什么我张贴了这个问题,多数民众赞成。当我们实现的接口,它的创建的方法表的新插槽,用于所述接口的方法呢?我们不应该被实施I2 ::画得太A类?

I'm not very confident about my answer, and thats why i'm posting this question. When we implement interfaces, it's created a new slot on the method table for the methods of said interface? shouldnt we be implementing I2::Draw too in class A?

同样,当我们调用使用接口变量(如i1.Draw())我明白,我们的方法'重新动态调度,因此,我们应该看看对象的类型正在举行的变量(A类在这种情况下)和搜索的方法表一个名为专门I1.Draw方法。但是,如果我们没有发现呢?我应该如何处理这些情况?有没有我应该知道,为了成功地解决这些问题拇指任何规则?

Likewise, when we call a method using an interface variable (like i1.Draw()) i understand we're on dynamic dispatch, and therefore we should look at the type of the object being held by the variable(type A in that case) and search A's method table for a method called specifically I1.Draw. But what if we don't find it? How should i proceed in these cases? Is there any rule of thumb i should know about in order to successfully tackle these issues?

对不起,是这个问题太无聊,但我真的需要解开这个心结在我的头上;!)

Sorry for being so boring with this question, but i really need to untie this knot on my head ;)

干杯

推荐答案

好问题。

要想想这是这样的:接口让自己的一套插槽。要求它实现一个接口的类来填补这些插槽。

The way to think about this is: interfaces get their own set of slots. A class which implements an interface is required to fill in those slots.


  • 接口I1有一个插槽,我们会打电话给I1SLOT。

  • 接口I1有一个插槽,我们会打电话给I2SLOT。

  • A类有它自己的,AMinSLOT和ADrawSLOT的两个插槽。

  • A类有三个方法,我们称之为AMinMethod,ADrawMethod和AI2DrawMethod。

  • 当你说新A,运行时拥有的插槽填写

  • I1SLOT与ADrawMethod填写。

  • I2SLOT与AI2DrawMethod填写。

  • AMinSLOT与AMinMethod填写。

  • ADrawSLOT与ADrawMethod填写。

  • b类有三个插槽。它继承AMinSLOT和ADrawSLOT,并确定了新的插槽,BDrawSLOT。

  • B类有两个方法,BDrawMethod和BI1DrawMethod。

  • 当你说新b运行时具有的五类的插槽填写

  • I1SLOT与BI1DrawMethod填写。

  • I2SLOT是与BDrawMethod填写。

  • AMinSLOT填充有AMinMethod。

  • ADrawSLOT填充有ADrawMethod。

  • BDrawSLOT与BDrawMethod填写。

  • Interface I1 has a slot we'll call I1SLOT.
  • Interface I1 has a slot we'll call I2SLOT.
  • Class A has two slots of its own, AMinSLOT and ADrawSLOT.
  • Class A has three methods, which we'll call AMinMethod, ADrawMethod and AI2DrawMethod.
  • When you say "new A", the runtime has four slots to fill in.
  • I1SLOT is filled in with ADrawMethod.
  • I2SLOT is filled in with AI2DrawMethod.
  • AMinSLOT is filled in with AMinMethod.
  • ADrawSLOT is filled in with ADrawMethod.
  • Class B has three slots. It inherits AMinSLOT and ADrawSLOT, and defines a new slot, BDrawSLOT.
  • Class B has two methods, BDrawMethod and BI1DrawMethod.
  • When you say "new B" the runtime has five slots to fill in.
  • I1SLOT is filled in with BI1DrawMethod.
  • I2SLOT is filled in with BDrawMethod.
  • AMinSLOT is filled in with AMinMethod.
  • ADrawSLOT is filled in with ADrawMethod.
  • BDrawSLOT is filled in with BDrawMethod.

现在还记得,重载解析的工作是选择基于类型的插槽中,参数。有没有参数,所以编译器只需要熄灭的类型。

Now remember, the job of overload resolution is to choose the slot based on the type and the arguments. There are no arguments, so the compiler only has the type to go off of.


  • 当你调用绘制的编译时的对象上A型,最好的搭配是ADrawSLOT。

  • 当你调用绘制编译时类型b的对象,最好的搭配是BDrawSLOT。

  • 当调用绘制编译时类型I1的对象,最好的搭配是I1SLOT。

  • 当你调用绘制编译时类型I2的对象,最好的搭配是I2SLOT。

  • When you call Draw on an object of compile-time type A, the best match is ADrawSLOT.
  • When you call Draw on an object of compile-time type B, the best match is BDrawSLOT.
  • When you call Draw on an object of compile-time type I1, the best match is I1SLOT.
  • When you call Draw on an object of compile-time type I2, the best match is I2SLOT.

和编译器产生的代码,说:叫什么方法是在运行时与所选的时段。

And the compiler generates code that says "call whatever method is in the chosen slot at runtime."

总结:

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

如果您有兴趣这是如何实现的,使用ILDASM拆开你的程序,再看看元数据表25(的0x19)的MethodImpl表。这项计划的MethodImplTable是:

If you're interested in how this is implemented, use ILDASM to disassemble your program, and then look at metadata table 25 (0x19), the MethodImpl table. This program's MethodImplTable is:

1 == 0:TypeDef[2000004], 1:MethodDefOrRef[06000005], 2:MethodDefOrRef[06000002]
2 == 0:TypeDef[2000005], 1:MethodDefOrRef[06000008], 2:MethodDefOrRef[06000001]

然后你可以看在的typedef和methoddef表,你会看到这个解码为:

Then you can look in the typedef and methoddef tables, and you'll see that this decodes as:

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



MethodImpl表是CLI如何代表我要坚持的东西在该插槽是比普通名称不同的概念匹配规则会选择。通常情况下,名称匹配规则会选择一个叫做画在插槽中,而不是I1.Draw或I2.Draw走法。

The MethodImpl table is how the CLI represents the notion of "I need to stick something in this slot that is different than what the regular name matching rules would choose". Normally the name matching rules would choose a method called "Draw" to go in that slot, not "I1.Draw" or "I2.Draw".

您还可能想读的CLI规范的分区Ⅱ第22.27。

You might also want to read section 22.27 of Partition II of the CLI spec.

这篇关于更多关于虚拟/新...加上接口!的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆