Какова реальная причина предотвращения доступа защищенного члена через базовый / родной класс?
Недавно я обнаружил, что метод в производном классе может получить доступ только к защищенным членам экземпляра базового класса через экземпляр производного класса (или один из его подклассов):
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».