我将A.Test()
声明为public virtual
, B.Test()
声明为private new
。
我从继承B
的C
调用base.Test()
。
这段代码可以在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#版本而变化?
这是有效的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中的F()。G是有效的,并且将调用Base.F.
我强烈怀疑Mono 2.10.2盲目地插入了对B.Test()
的调用——不是因为它看到了私有方法的存在,而只是为了确保调用了基类方法。碰巧的是,这在执行时很糟糕。关于调用哪个基类方法的选择是一个有趣的选择,因为B
可以在C的编译时间和执行时间之间改变,以覆盖Test()
…在这一点上,行为是不明显的。Eric Lippert在一篇博客文章中谈到了这一点,你可能会觉得很有趣。