Какова реальная причина предотвращения доступа защищенного члена через базовый / родной класс?

Недавно я обнаружил, что метод в производном классе может получить доступ только к защищенным членам экземпляра базового класса через экземпляр производного класса (или один из его подклассов):

class Base
{
    protected virtual void Member() { }
}

class MyDerived : Base
{
    // error CS1540
    void Test(Base b) { b.Member(); }
    // error CS1540
    void Test(YourDerived yd) { yd.Member(); }

    // OK
    void Test(MyDerived md) { md.Member(); }
    // OK
    void Test(MySuperDerived msd) { msd.Member(); }
}

class MySuperDerived : MyDerived { }

class YourDerived : Base { }

Мне удалось обойти это ограничение, добавив статический метод в базовый класс, поскольку методам Base разрешен доступ к Base.Member, и MyDerived может вызывать этот статический метод.

Я до сих пор не понимаю причину этого ограничения, хотя. Я видел несколько разных объяснений, но они не могут объяснить, почему MyDerived.Test () по-прежнему разрешен доступ к MySuperDerived.Member.

Принципиальное объяснение:«Защищенный» означает, что он доступен только этому классу и его подклассам. YourDerivedмог переопределите Member (), создав новый метод, который должен быть доступен только для YourDerived и его подклассов. MyDerived не может вызвать переопределенный метод yd.Member (), поскольку он не является подклассом YourDerived, и он не может вызвать b.Member (), поскольку b может фактически быть экземпляром YourDerived.

Хорошо, но тогда почему MyDerived может вызвать msd.Member ()? MySuperDerived может переопределить Member (), и это переопределение должно быть доступно только для MySuperDerived и его подклассов, верно?

Вы до конца времени не знаете, вызываете ли вы переопределенный член или нет. И когда элемент является полем, он все равно не может быть переопределен, но доступ по-прежнему запрещен.

Прагматическое объяснение:Другие классы могут добавлять инварианты, о которых ваш класс не знает, и вы должны использовать их открытый интерфейс, чтобы они могли поддерживать эти инварианты. Если бы MyDerived мог иметь прямой доступ к защищенным членам YourDerived, он мог бы сломать эти инварианты.

Мое же возражение применимо и здесь. MyDerived также не знает, какие инварианты мог бы добавить MySuperDerived - он может быть определен в другой сборке другим автором - так почему MyDerived имеет прямой доступ к своим защищенным элементам?

У меня складывается впечатление, что это ограничение времени компиляции существует как ошибочная попытка решить проблему, которая действительно может быть решена только во время выполнения. Но, возможно, я что-то упустил. У кого-нибудь есть пример проблемы, которая может быть вызвана тем, что MyDerived будет иметь доступ к защищенным элементам Base через переменную типа YourDerived или Base, ноне уже существует при доступе к ним через переменную типа MyDerived или MySuperDerived?

-

ОБНОВЛЕНИЕ: я знаю, что компилятор просто следует спецификации языка; то, что я хочу знать, является целью этой части спецификации. Идеальным ответом было бы: «Если бы MyDerived мог вызвать YourDerived.Member (), произойдет $ NIGHTMARE, но этого не произойдет при вызове MySuperDerived.Member (), потому что $ ITSALLGOOD».

Ответы на вопрос(6)

Ваш ответ на вопрос