输出:
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."的原因是,你还没有覆盖的类ToStringB方法,您已使用new关键字阴影它。因此,B类有两个ToString方法,一是从类A和一个阴影它继承。如果使用A参考调用ToString方法,继承的方法被调用,但如果你会使用一个B参考调用它,遮蔽方法将被调用,打印出"This is class B."

此外,如果你覆盖在类ToString代替遮蔽它的B方法,这将打印出"This is class B."不管引用的类型的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top