4

我已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# 版本而异?

4

1 回答 1

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 在一篇您可能会感兴趣的博客文章中谈到了这一点。

于 2013-04-30T21:40:50.683 回答