C# 更多关于虚拟/新…以及接口的信息!
昨天我发布了一个关于new/virtual/override关键字的问题,我从你的回答中学到了很多。但我仍然有些怀疑 在所有“框”之间,我与类型的方法表的实际情况失去了联系。例如:C# 更多关于虚拟/新…以及接口的信息!,c#,interface,virtual,overriding,new-operator,C#,Interface,Virtual,Overriding,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 v
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()生成的输出
我的回答是:
在类型A中,我们有3个方法:MinInstance()、Draw()——A::Draw版本——和I2::Draw
在类型B中,我们有4个方法:来自A的MinInstance、B::Draw、I1::Draw和I2::Draw
我对我的答案不是很有信心,这就是为什么我要发布这个问题。当我们实现接口时,它在方法表上为所述接口的方法创建了一个新槽?我们不应该在类A中实现I2::Draw吗
同样,当我们使用接口变量(如i1.Draw())调用方法时,我知道我们处于动态调度状态,因此我们应该查看变量所持有的对象的类型(在这种情况下为类型a),并在a的方法表中搜索一个名为i1.Draw的方法。但是如果我们找不到呢?在这些情况下,我应该如何处理?为了成功地解决这些问题,我应该知道什么经验法则吗
对不起,这个问题太无聊了,但我真的需要解开我头上的这个结;)
干杯 据我所知,您在问,给定一个具有一些重写方法的子类,如何知道将调用哪个方法 基本上,我可以想到三种选择:
I1
和I2
的契约可以用相同的Draw
方法来满足,并且将会满足,除非您使用隐式实现将它们分开,这里就是这种情况。如果没有这一点,一个绘图
方法就可以了
在所有情况下,公共
绘图将被调用,除非引用被转换为显式实现的接口类型。除了其他答案之外,我发布了一个正确的答案:
A a = new B();
a.Draw(); //A::Draw
I1 i1 = new A();
i1.Draw(); //A::Draw
I2 i2 = new B();
i2.Draw();// B::Draw
B b = (B) a;
b.Draw();// B::Draw
注释和参考:我必须回到标准(ECMA-334)中,在§20.4.4接口重新实现中可以找到:
允许继承接口实现的类通过将接口包含在基类列表中来重新实现接口
接口的重新实现遵循与接口的初始实现完全相同的接口映射规则。因此,继承的接口映射对为重新实现接口而建立的接口映射没有任何影响。[示例:在声明中]
Control
将IControl.Paint
映射到Control.IControl.Paint
上的事实并不影响在MyControl
中重新实现,它将IControl.Paint
映射到MyControl.Paint
上
继承的公共成员声明和继承的显式接口成员声明参与重新实现接口的接口映射过程。[示例:
这里,Derived
中IMethods
的实现将接口方法映射到Derived.F
、Base.IMethods.G
、Derived.IMethods.H
和Base.I
。结束示例]
当一个类实现一个接口时,它还隐式地实现该接口的所有基接口。同样,接口的重新实现也隐含着接口的所有基本接口的重新实现。[示例:
这里,IDerived
的重新实现也重新实现了IBase
,将IBase.F
映射到D.F
。结束示例]
好问题
考虑这一点的方法是:接口有自己的插槽集。需要一个实现接口的类来填充这些插槽
- 接口I1有一个插槽,我们称之为I1SLOT
- 接口I1有一个插槽,我们称之为I2SLOT
- A类有自己的两个插槽,AMinSLOT和ADRAWSOT
- 类有三个方法,我们称之为AMinMethod、ADrawMethod和AI2DrawMethod
- 当您说“newa”时,运行时有四个插槽需要填充
- I1SLOT用ADrawMethod填充
- I2SLOT用AI2DRAW方法填充
- AMinSLOT用AMinMethod填充
- ADrawSLOT用ADrawMethod填充
- B班有三个座位。它继承了AMinSLOT和ADrawSLOT,并定义了一个新的插槽BDrawSLOT
- 类B有两个方法,BDrawMethod和BI1DrawMethod
- 当你说“new B”时,运行时有五个插槽需要填充
- I1SLOT用BI1Draw方法填写
- I2SLOT用BDrawMethod填充
- AMinSLOT用AMinMethod填充
- ADrawSLOT用ADrawMethod填充
- BDrawSLOT用BDrawMethod填充。
interface I1 { void Draw(); }
interface I2 { void Draw(); }
class A : I1, I2
{
// this is just a method in A
public void Minstance() { Console.WriteLine("A::MInstance"); }
// method in A, also implements I1.Draw. May be overridden in
// derived types.
public virtual void Draw() { Console.WriteLine("A::Draw"); }
// implements I2.Draw, accessible on object a of type A via ((I2)a).Draw()
void I2.Draw() { Console.WriteLine("A::I2.Draw"); }
}
class B : A, I1, I2
{
// new method in B, does not override A.Draw, so A.Draw is only
// callable on an object b of type B via ((A)b).Draw(). Types
// derived from B may override this method, but can't override
// A.Draw because it's hidden. Also implements I2.Draw (see notes).
public new virtual void Draw() { Console.WriteLine("B::Draw"); }
// implements I1.Draw, accessible on object b of type B via ((I1)b).Draw()
void I1.Draw() { Console.WriteLine("B::I2.Draw"); }
}
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() {…}
}
class MyControl: Control, IControl
{
public void Paint() {}
}
interface IMethods
{
void F();
void G();
void H();
void I();
}
class Base: IMethods
{
void IMethods.F() {}
void IMethods.G() {}
public void H() {}
public void I() {}
}
class Derived: Base, IMethods
{
public void F() {}
void IMethods.H() {}
}
interface IBase
{
void F();
}
interface IDerived: IBase
{
void G();
}
class C: IDerived
{
void IBase.F() {…}
void IDerived.G() {…}
}
class D: C, IDerived
{
public void F() {…}
public void G() {…}
}
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
1 == 0:TypeDef[2000004], 1:MethodDefOrRef[06000005], 2:MethodDefOrRef[06000002]
2 == 0:TypeDef[2000005], 1:MethodDefOrRef[06000008], 2:MethodDefOrRef[06000001]
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
A a2= new B() (creates a new object using constructor of B, because b is of type A, therefore it works )
and a2.draw() will result in execution of A class draw because the type is A.