C# - 具有继承的显式接口?

时间:2009-12-06 20:33:58

标签: c# inheritance explicit-interface

输出:
B->您好!来自明确。

不应该是:?
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();
    }
}

4 个答案:

答案 0 :(得分:20)

不,它不应该。

Hello的调用等同于已注释的调用 - 获取IHello的路径无关紧要(除非它需要执行时间检查或转换);编译时类型只是IHello,无论如何,接口映射都是相同的。

当在类型层次结构中多次显式实现接口时,将使用最派生类型的实现。 (通过界面调用时。)

来自C#3.0规范的第13.4.4节:

  

类或的接口映射   struct C找到一个实现   每个接口的每个成员   在C的基类列表中指定   特定的实施   接口成员I.M,我在哪里   成员M所在的界面   声明,是通过检查确定的   每个类或结构S,以。开头   C并重复每次连续   C的基类,直到匹配为止   位于:

     
      
  • 如果S包含声明   显式接口成员   与I和M匹配的实现,   然后这个成员就是实施   of I.M。
  •   
  • 否则,如果S包含与M匹配的非静态公共成员的声明,则此成员是IM的实现如果多个成员匹配,则未指定哪个成员是IM的实现这种情况只能如果S是一个构造类型,其中泛型类型中声明的两个成员具有不同的签名,但类型参数使它们的签名相同,则会发生。
  •   

答案 1 :(得分:3)

(A)a什么都不做。该引用已经声明为将其转换为A将无效。

即使您的引用声明为A,它引用的对象也是B类型。如果将此对象转换为IHello,则调用Hello()将调用对象B的Hello的显式实现。

输出完全符合预期。

答案 2 :(得分:0)

不,当您创建方法(ToString)时,它不是虚拟的。新的只是意味着你不介意它“隐藏”基类中的版本 - 所以如果你使用你已经转换为特定类型(A)的引用来调用它,它会执行类A中的方法,而不管您正在调用的对象的实际类型。 (即你调用了A.ToString(),所以它执行了A.ToString())

当您创建虚拟方法时,无论您将引用类型转换为什么类型,都会使用来自实际对象类型的实现(即您创建了B,因此当您调用时(无论对象是什么)。你好,它叫做B.Hello)

关键的区别在于一个呼叫是虚拟呼叫而另一个呼叫不是。

答案 3 :(得分:0)

不,它不应该。

当您调用虚方法时,引用的类型无关紧要。调用的方法取决于对象的实际类型,而不是引用的类型。

在创建类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."