这个C#代码合法吗?

时间:2013-04-30 21:33:42

标签: c# .net mono c#-5.0 methodaccessexception

我将A.Test()声明为public virtualB.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#版本而变化?

1 个答案:

答案 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中讨论了这个问题,你可能会感兴趣。