C# - 带有继承的显式接口?
-
13-09-2019 - |
题
输出:
B->你好!来自显式。
不应该是:?
A->你好!来自显式。
为什么不从 A 类显式转换 (IHello)a 调用 IHello.Hello() ?
interface IHello
{
void Hello();
}
class A : IHello
{
public virtual void Hello()
{
Console.WriteLine("A->Hello!");
}
void IHello.Hello()
{
Console.WriteLine("A->Hello! from Explicit.");
}
}
class B : A, IHello
{
public override void Hello()
{
Console.WriteLine("B->Hello!");
}
void IHello.Hello()
{
Console.WriteLine("B->Hello! from Explicit.");
}
}
class Program
{
static void Main(string[] args)
{
A a = new B();
((IHello)a).Hello();
}
}
解决方案
不,不应该。
致电给 Hello
相当于注释掉的 - 获得的途径 IHello
没关系(除非需要执行时检查或转换);编译时类型只是 IHello
无论哪种方式,无论您到达那里,接口映射都是相同的。
当接口在类型层次结构中显式实现多次时,将使用最派生类型中的实现。(通过接口调用时。)
来自 C# 3.0 规范第 13.4.4 节:
类的接口映射或 struct C 查找 每个接口的每个成员 在 C 的基类列表中指定。特定 接口成员 I.M,其中 I 是 成员 M 所在的接口 声明,通过检查确定 每个类或结构 S,以 C 并重复每个连续的 C 的基类,直到匹配 位于:
- 如果S包含与I和M匹配的显式接口成员实现的声明,则此成员是IM的实现
- 否则,如果 S 包含与 M 匹配的非静态公共成员的声明,则该成员是 I.M 的实现。如果有多个成员匹配,则未指定哪个成员是 I.M. 的实现。仅当 S 是构造类型时才会发生这种情况,其中泛型类型中声明的两个成员具有不同的签名,但类型参数使它们的签名相同。
其他提示
(A)一个什么都不做。参考已经被声明为一个,因此投射到A将没有任何效果。
即使您参考被声明为A,它是指该对象是B型的。如果你施放此对象IHello,你好(呼叫)将调用对象B的显式实现你好的。
是完全一样的预期的输出。
没有,在创建的新方式(的ToString),它不是虚拟的。新只是意味着你不介意它“隐藏”在基类的版本 - 如果你与你已经转换为特定类型(A)的引用调用它,它执行A类的方法,无论实际类型您呼叫的对象。 (即你称为A.ToString(),所以它执行A.ToString())
当创建的虚拟方式,则无论是什么类型的你施放的参考,从实际类型对象的实现,则使用(即创建一个B,所以当你打电话(无论对象是).Hello,它称为B.Hello)
关键的区别在于,一个呼叫是虚拟,而另一个不是。
没有,它不应该。
当要调用虚拟方法,它并不重要基准的类型是什么。时调用的方法是由实际类型对象,而不是引用的类型的确定。
当创建类B
的一个实例中,对象的实际类型是B
。它打印"This is class A."
的原因是,你还没有覆盖的类ToString
的B
方法,您已使用new
关键字阴影它。因此,B
类有两个ToString
方法,一是从类A
和一个阴影它继承。如果使用A
参考调用ToString
方法,继承的方法被调用,但如果你会使用一个B
参考调用它,遮蔽方法将被调用,打印出"This is class B."
。
此外,如果你覆盖在类ToString
代替遮蔽它的B
方法,这将打印出"This is class B."
不管引用的类型的。