我将A.Test()
声明为public virtual
,B.Test()
声明为private new
。
我正在base.Test()
致电C
,继承B
。
此代码使用Mono 2.10.2进行编译,但会抛出MethodAccessException
:
class A {
public virtual void Test () { }
}
class B : A {
private new void Test () { }
}
class C : B {
public C ()
{
base.Test ();
}
public static void Main (string[] args)
{
var c = new C ();
}
}
以下是我得到的例外情况:
System.MethodAccessException: Method TestBug.B:Test () is inaccessible from method TestBug.C:.ctor ()
这是正确的行为吗?
这是在Microsoft .NET中编译还是使用较新版本的Mono编译?
C#规范对此有何看法?
它是否随C#版本而变化?
答案 0 :(得分:12)
它是有效的C#,但是Mono 2.10.2编译器显然做错了。使用MS编译器,对base.Test()
的调用将编译为:
IL_0008: ldarg.0
IL_0009: call instance void A::Test()
Mono 3.0.6.0编译器的工作方式相同。
就A
而言,B.Test()
实际上并不存在。
事实上,C#5规范的第3.7节甚至提供了一个显式示例,它与您的非常相似:
新成员的声明仅在新成员的范围内隐藏继承的成员。
class Base { public static void F() {} } class Derived: Base { new private static void F() {} // Hides Base.F in Derived only } class MoreDerived: Derived { static void G() { F(); } // Invokes Base.F }
在上面的示例中,Derived中的F声明隐藏了从Base继承的F,但由于Derived中的新F具有私有访问权限,因此其范围不会扩展到MoreDerived。因此,MoreDerived.G中的调用F()是有效的,并将调用Base.F。
我强烈怀疑Mono 2.10.2盲目地插入对B.Test()
的调用 - 不是因为它看到了私有方法的存在,而是为了确保“调用基类方法”。碰巧的是,这在执行时非常糟糕。选择调用哪个基类方法是一个有趣的方法,因为B
可以在C的编译时和执行时间之间进行更改,以覆盖Test()
...指出行为是不明显的。 Eric Lippert在blog post中讨论了这个问题,你可能会感兴趣。