2013-04-30 4 views
4

У меня есть A.Test(), объявленный как public virtual и B.Test(), объявленный как private new.
Я звоню base.Test() от C, который наследует B.Является ли этот код C# законным?

Этот код компилируется с 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# spec?
Это зависит от версии C#?

+1

Вы не можете получить доступ к 'private' в подклассе, если вы хотите, чтобы этот метод был скрыт с другим, но доступным в подклассе, u должен использовать' protected' –

+0

. Что вы пытаетесь сделать? Доступ к общедоступному методу A.Test из класса внуков C? – statueuphemism

+0

Похоже, что это ошибка в версии Mono, которую вы используете. –

ответ

12

Это действительно C#, но компилятор Mono 2.10.2, по-видимому, делает неправильную вещь. С MS компилятором, вызов base.Test() компилируется:

IL_0008: ldarg.0 
IL_0009: call  instance void A::Test() 

Моно 3.0.6.0 компилятор работает точно так же.

Что касается A, то B.Test() фактически не существует.

В самом деле, раздел 3.7 C# 5 спецификации даже дает явный пример, который очень похож на ваш:

Заявление нового члена скрывает унаследованный член только в пределах объема настоящего новый участник.

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 
} 

В приведенном выше примере, объявление F в производный скрывает F, унаследованный от базы, но так как новый F в Derived имеет частный доступ, сфера его применения не распространяется на MoreDerived. Таким образом, вызов F() в MoreDerived.G действителен и будет ссылаться на Base.F.

Я сильно подозреваю, что Mono 2.10.2 вслепую вставив вызов B.Test() - не потому, что он видит существование частного метода, но только для того, чтобы «метод базового класса называется». Как это бывает, это происходит во время выполнения. Выбор метода базового класса для вызова является интересным, так как Bможет изменить время компиляции C и время выполнения, переопределить Test() ..., в этот момент поведение неочевидно. Эрик Липперт говорит об этом в blog post, который может показаться вам интересным.

+0

Он пропустил уровень? Зачем? – Jasmine

+1

@Jasmine: Потому что 'B.Test()' является закрытым. Это даже не видно «C»; 'C' не знает, что он существует, поэтому он вызывает метод, о котором он * знает. –

+0

@ Jon, спасибо, что пришли! Это действительно очень полезно, потому что я не могу перейти на Mono 3 на данный момент. Думаю, в моем случае быстрым решением было бы изменить 'base.Test()' на 'this.Test()' ('C' не переопределяет' Test', поэтому в любом случае это не имеет значения). –

Смежные вопросы