输出:
B->您好!来自明确。
不应该是:?
A->您好!来自明确。
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();
}
}
答案 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."
。