Почему мы не можем изменять модификатор доступа при переопределении методов в C #?

В C # мы не можем изменить модификатор доступа, переопределяя метод из базового classа. например

Class Base { **protected** string foo() { return "Base"; } } Class Derived : Base { **public** override string foo() { return "Derived"; } } 

Это недействительно в C #, это даст ошибку времени компиляции.

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

Изменение модификатора доступа метода в производном типе бессмысленно, поэтому его недопустимо:

Случай 1: переопределение с более ограничительным доступом

Этот случай, очевидно, не допускается из-за следующей ситуации:

 class Base { public virtual void A() {} } class Derived: Base { protected override void A() } 

Теперь мы могли бы сказать:

 List list; list.Add(new Derived()); list[0].A() //Runtime access exception 

Случай 2: переопределение с менее ограничительным модификатором доступа

В чем смысл? Скройте метод, и все готово. Очевидно, что если кто-то звонит через базовый тип, у них не будет доступа к новому методу, определенному в производном типе, но это согласуется с тем, как автор базового типа хотел, чтобы все было так, чтобы у вас не было «права», чтобы изменить это. Если вам нужна спецификация вызова производного classа из производного classа, в этом случае new метод работает отлично.

EDIT: расширение корпуса 2

То, что я пытаюсь сказать в случае 2, заключается в том, что у вас уже есть средства для изменения доступности любого метода (виртуального или нет), если вы хотите изменить доступность.

Рассмотрим следующий код:

 public class Base { protected virtual string WhoAmI() { return "Base"; } } public class Derived : Base { public new virtual string WhoAmI() { return "Derived"; } } public class AnotherDerived : Derived { public override string WhoAmI() { return "AnotherDerived"; } } 

С помощью new ключевого слова вы эффективно создали новый виртуальный метод для вашего classа Derived с тем же именем и подписью. Обратите внимание, что ДОЛЖНО объявить new метод virtual , поэтому любому classу, полученному из Derived будет разрешено переопределить его.

То, что не допускается, – это заставить кого-то сделать следующее:

  Base newBaseObject = new Derived(); newBaseObject.WhoAmI() //WhoAmI is not accessible. 

Но этот факт не имеет ничего общего с возможностью переопределения WhoAmI() или нет. В любом случае эта ситуация никогда не может быть вызвана тем, что Base не объявляет public WhoAmI() .

Таким образом, в теоретическом C #, где Derived.WhoAmI() может переопределять Base.WhoAmI() в этом нет никаких практических преимуществ, потому что вы никогда не сможете вызывать виртуальный метод из базового classа в любом случае, так что new вариант уже соответствует вашим требования.

Надеюсь, это станет более ясным.

Хорошо, я нашел небольшую заметку от Эрика Липперта в аннотированной ссылке на C #:

Переопределенный виртуальный метод по-прежнему считается методом classа, который его представил. Правила разрешения перегрузки в некоторых случаях предпочитают члены более производных типов … переопределение метода не «перемещается», если этот метод принадлежит этой иерархии.

Таким образом, это преднамеренное правило для предотвращения проблемы «хрупкого базового classа» и обеспечения лучшего управления версиями, то есть меньше проблем при изменении базового classа.

Но обратите внимание, что это не имеет ничего общего с безопасностью, безопасностью типа или состоянием объекта.

Если вы изменяете модификаторы видимости от более ограничивающего модификатора до менее ограничивающего модификатора, вы позволяете клиентам classа обращаться к методам, предназначенным для внутреннего использования. По сути, вы предоставили средство для изменения состояния classа, которое может быть небезопасным.

Вы можете сделать доступ к производному classу меньше, чем базовый, но не более. В противном случае это противоречило бы определению базы и раскрыло бы ее компоненты за пределами того, что было предназначено.

Уменьшение видимости невозможно, потому что, если Base.Member был виден, а Derived.Member не был виден, это Derived.Member бы концепцию « Derived is a Base » в ООП. Однако увеличение видимости запрещено, возможно, потому, что разработчики языка считают, что изменение видимости было бы ошибкой большую часть времени. Тем не менее, вы всегда можете использовать new ключевое слово, чтобы скрыть элементы базового classа, введя член с тем же именем, но с другим поведением. Этот новый член принадлежит интерфейсу производного типа, поэтому, конечно, вы все равно можете получить доступ к интерфейсу базового типа, перейдя на этот базовый тип. В зависимости от того, как вы пишете свой подclass, ваш new член может эффективно увеличить видимость свойства базового classа, но помните, что к свойству базового classа все еще можно получить доступ напрямую (например, подclass вашего подclassа может отнести this к Base и обходить ваш имущество).

Здесь задается вопрос о том, как и override и override и тот же элемент (идентификатор) в подclass. Это, по-видимому, невозможно. По крайней мере, я могу сказать посредством экспериментов, что public new override string foo(){return "";} не является синтаксисом для этого. Однако вы можете получить тот же эффект, используя два подclassа:

 using System; class Base { protected virtual string foo() { return "Base"; } public void ExhibitSubclassDependentBehavior() { Console.WriteLine("Hi, I am {0} and {1}.", GetType(), foo()); } } abstract class AbstractDerived : Base { protected virtual string AbstractFoo() { return base.foo(); } protected override string foo() { return AbstractFoo(); } } class Derived : AbstractDerived { protected override string AbstractFoo() { return "Deprived"; } public new string foo() { return AbstractFoo(); } } static class Program { public static void Main(string[] args) { var b = new Base(); var d = new Derived(); Base derivedAsBase = d; Console.Write(nameof(b) + " -> "); b.ExhibitSubclassDependentBehavior(); // "b -> Hi, I am Base and Base." Console.WriteLine(nameof(d) + " -> " + d.foo()); // "d -> Deprived" Console.Write(nameof(derivedAsBase) + " -> "); derivedAsBase.ExhibitSubclassDependentBehavior(); // "derivedAsBase -> Hi, I am Derived and Deprived." } } 

В промежуточном подclassе ( AbstractDerived ) используется override и вводится новый, иначе называемый элемент, который подclass и подclassы могут продолжать override член базового classа по своему усмотрению. Под-подclass ( Derived ) использует new для внедрения нового API. Поскольку вы можете использовать new или override с определенным идентификатором только один раз за уровень подclassа, вам необходимо два уровня подclassа, чтобы эффективно использовать оба параметра для одного и того же идентификатора.

Таким образом, вы можете изменить видимость при переопределении методов – это просто боль, и я не знаю синтаксиса, чтобы выполнить его только с одним уровнем наследования. Однако, возможно, вам придется использовать какой-то трюк, подобный этому, в зависимости от того, какие интерфейсы вы пытаетесь реализовать и как выглядит ваш базовый class. То есть, это может быть или не быть тем, что вы на самом деле хотите сделать. Но я все еще удивляюсь, почему C # не просто поддерживает это для начала. IOW, этот «ответ» – это просто повторное выражение вопроса OP с обходным решением ;-).

Причины очевидны. Безопасность и целостность объектов.

В этом конкретном примере, что, если внешние объекты начинают изменять свойство объекта, который защищен в соответствии с базовым classом. Вещи пойдут поглубже. Что относительно клиентского кода, который написан против базового classа, которому должен соответствовать весь / любой производный class.

если у него были разные модификаторы доступа, вы не можете больше рассматривать его таким же способом. вид предполагает проблему с дизайном модели.

лучший вопрос – почему вы хотите изменить модификаторы доступа?

Переопределение – это термин, который позволяет вам изменять или дополнять поведение методов в базовом classе. Переопределение дает вам возможность писать новую логику для существующего метода.

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

Interesting Posts

Как остановить / # / в браузере с помощью ретранслятора?

Панель прогресса Android WebView

Есть ли недостаток в добавлении анонимного пустого делегата в объявление события?

Получить текущую папку с помощью команды DOS?

Сделать вызов Https с помощью HttpClient

Почему я получаю «алгоритм не сходился» и «устанавливал prob численно 0 или 1» предупреждения с помощью glm?

Как читать текст из скрытого элемента с помощью Selenium WebDriver?

Каков самый простой способ преобразования массива в вектор?

Как освободить память после того, как BitmapImage больше не нужен?

Разница между AlarmManager и ScheduledExecutorService

Реверсивный алгоритм тасования с использованием ключа

Не удается избежать обратного слэша с помощью регулярного выражения?

Использование VideoView для streamовой или прогрессивной загрузки видео

Что делает Option Strict и Option Explicit?

Автоматически шифровать и расшифровывать электронные письма с помощью gnupg (gpgrelay для unix)

Давайте будем гением компьютера.