Перекрывающий защищенный внутренний с защищенным! - PullRequest
27 голосов
/ 04 марта 2010

Это extension для этого вопроса , заданного час назад.

Мы не можем изменить access modifiers при переопределении virtual method в derived классе. Рассмотрим Control класс в System.Web.UI пространстве имен

public class Control : IComponent, IDisposable,...
{ 
   protected internal virtual void CreateChildControls()
   { }
   .
   .
}

Теперь рассмотрим это

public class someClass : System.Web.UI.Control
    { 
       // This should not compile but it does
        protected override void CreateChildControls()
        { }

       // This should compile but it does not
        protected internal override void CreateChildControls()
        { }  
    }

Может ли кто-нибудь объяснить это? Спасибо

Ответы [ 3 ]

48 голосов
/ 04 марта 2010

Мы не можем изменять модификаторы доступа при переопределении виртуального метода в производном классе.

Это утверждение неверно. Вы можете и должны изменить модификаторы доступа, когда именно в описанной вами ситуации. В других ситуациях нельзя изменять модификаторы доступа.

Я отсылаю вас к разделу 10.6.4 спецификации, в котором говорится:

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

Аргументация проста.

У вас, Асад, есть банковский счет, банковский счет.

У вас есть дом. Вы снимаете комнату в доме у вашего лучшего друга Чарли.

У Чарли есть сын Дэвид, который живет в квартире.

У вас есть сын, Элрой, который живет в квартире.

У Элроя есть сын, твой внук, Фрэнк, который живет в юрте.

У Элроя есть лучший друг Грег, который живет с ним в квартире.

Вы предоставляете доступ к своей банковской учетной записи себе, всем, кто живет в доме, и любому из ваших потомков. Таким образом, люди, которые могут получить доступ к банковскому счету, - это Асад, Чарли, Элрой и Фрэнк.

Дэвид не получает доступа, потому что он не ты, не твой потомок и не живет в Доме. То, что он ребенок вашего соседа по дому, не имеет значения; он не получает доступ к вашему банковскому счету.

Грег также не получает доступ к вашему банковскому счету. Он не твой потомок. Он не живет в доме. Тот факт, что он живет с вашим потомком, не дает ему таких же прав, как у вашего потомка.

Теперь мы подошли к сути вопроса. Элрой не разрешено расширять доступ к вашему банковскому счету Грегу. У вас есть этот банковский счет, и вы сказали "я, мои потомки и мои соседи по дому". Ваши дети не имеют права расширять доступ к BankAccount сверх того, что вы изначально установили.

Когда Элрой описывает, какой у него доступ к BankAccount, ему разрешается только сказать «я даю доступ к этому себе и своим потомкам», потому что это то, что вы уже разрешили. Он не может сказать: «Я предоставляю доступ к BankAccount себе, своим потомкам и другим жителям Кондо».

Просто чтобы прояснить:

  • Я и мои потомки получаем доступ = защищенный доступ
  • Я и мои соседи по дому получают доступ = внутренний доступ
  • Я, мои потомки и соседи по дому получают доступ = защищенный внутренний доступ
  • Контроль = Асад
  • CreateChildControls = BankAccount
  • House = System.Web.DLL
  • Чарли = любой тип в System.Web.DLL
  • Дэвид = производный тип Чарли в сборке Apartment.DLL
  • Elroy = someClass
  • Condo = ваша сборка, содержащая SomeClass
  • Greg = какой-то другой класс в Condo.DLL
  • Frank = производный тип someClass в Yurt.DLL
  • юрта = какая-то другая сборка
6 голосов
/ 04 марта 2010

Потому что, хотя терминология иная, переопределение ее как protected сохраняет видимость члена неизменной. Если бы вам было разрешено переопределить его как protected internal, вы бы внезапно открыли для элемента любой другой тип в вашей сборке.

3 голосов
/ 04 марта 2010

Защищенный внутренний означает защищенный ИЛИ внутренний. Поэтому, если при переопределении вне исходной сборки вам будет разрешено пометить ее как внутреннюю защищенную, вы позволите другим классам в той же сборке, что и переопределитель, вызывать этот метод. Это фактически означает, что внутренняя инкапсуляция оригинального родителя будет нарушена.

...