Замечу, что здесь есть два вопроса.В будущем вы можете рассмотреть возможность размещения двух вопросов вместо объединения двух вопросов в один.Когда вы часто комбинируете такие вопросы, то получается только первый ответ.
Первый вопрос: «Почему частные виртуальные методы недопустимы в C #?»
Вот аргументы противФункция «частные виртуальные методы»:
Частная виртуальная полезна, только если у вас есть вложенный производный класс.Это полезный шаблон, но гораздо менее распространенный, чем ситуация с не вложенным производным классом.
Если вы хотите ограничить возможность переопределить метод в не-внесенные производные классы, тогда вы можете сделать это, ограничив способность не вложенных классов наследовать от базового класса;сделать все конструкторы базового класса приватными.Поэтому частный виртуальный не является необходимым для предотвращения переопределения;защищенного виртуального достаточно, потому что будут вложены только производные классы.
Если вы хотите ограничить возможность вызывать метод в не вложенном производном классезатем вы можете сделать метод внутренним виртуальным, а затем попросить коллег не использовать этот метод.Раздражает, что компилятор не применяет это, но компилятор не устанавливает никаких других семантических ограничений на то, как метод должен использоваться;Правильная семантика - это ваше дело, а не компилятор, и вы должны обеспечить это с помощью соответствующих обзоров кода.Поэтому частный виртуальный не требуется, чтобы предотвратить вызовы;достаточно обзоров внутреннего виртуального кода плюс.
Возможно реализовать этот шаблон уже с существующими частями:
abstract class C
{
private int CF() { whatever; }
private Func<int> f;
public C() { f = CF; }
private int F() { return f(); }
private class D : C
{
private int DF() { whatever; }
public D() { f = DF; }
}
Теперь у меня есть метод F, который эффективно виртуально, но может быть «переопределено» только производными вложенными классами.
Поскольку в любом случае используется либо защищенный, внутренний или защищенный внутренний, частный виртуальныйненужным.Это почти никогда не правильно, поскольку вы уже должны быть привержены использованию шаблона вложенного производного класса.Итак, язык делает его недопустимым.
Аргументы для:
В реальном коде были моменты, когда я хотел, чтобы виртуальный метод был частной деталью реализации класса, которыйЯ хочу расширяться как не вложенными внутренними классами, так и вложенными внутренними классами.Необходимость применять инвариант, чтобы мои коллеги не вызывали внутренний метод, раздражает;Я бы хотел, чтобы это обеспечивалось компилятором, чтобы мне не приходилось прыгать через сумасшедшие циклы, такие как создание поля типа делегата и т. Д.
Кроме того, существует просто вопрос согласованности и ортогональности.Кажется странным, что две вещи, которые должны быть независимыми, - доступность и виртуальность - без необходимости влияют друг на друга.
Аргументы против этой функции довольно сильны.Аргументы в пользу довольно слабые.Поэтому такой функции нет.Мне лично это очень нравится, но я полностью понимаю, почему команда дизайнеров никогда не брала меня с собой.Это не стоит затрат, и я бы не хотел, чтобы , а не поставляли лучшую функцию, потому что мы потратили бюджет на функцию, которая почти никому не нужна.
Второй вопрос: «Почему в C #Вы не можете переопределить закрытый виртуальный метод в производном не вложенном классе? "
Есть несколько причин.
Поскольку вы можете переопределить только то, что видите,Закрытый метод - это частная деталь реализации базового класса, и он не должен быть доступен.
Потому что разрешение этого имеет серьезные последствия для безопасности. Помните, что в C ++ вы почти всегда компилируете код в приложение одновременно. У вас есть исходный код для всего; все по сути "внутреннее" с точки зрения C ++ большую часть времени. В C # это совсем не так. Сторонние сборки могут легко получить открытые типы из библиотек и создавать новые расширения для этих классов, которые затем можно беспрепятственно использовать вместо экземпляров базового класса. Поскольку виртуальные методы эффективно изменяют поведение класса, любой код, который по соображениям безопасности зависит от инвариантов этого класса, должен быть тщательно спроектирован, чтобы они не зависели от инвариантов, гарантируемых базовым классом. Ограничение доступности виртуальных методов помогает обеспечить сохранение инвариантов этих методов.
Потому что разрешение этого предоставляет другую форму проблемы хрупкого базового класса. C # был тщательно разработан, чтобы быть менее восприимчивым к хрупкой проблеме базового класса, чем другие языки OO. Если недоступный виртуальный метод может быть переопределен в производном классе, то эта частная деталь реализации базового класса станет критическим изменением, если оно будет изменено. Поставщики базовых классов должны иметь возможность изменять свои внутренние детали, не беспокоясь о том, что они нарушили производные классы, которые зависят от них; в идеале, при изменении деталей реализации необходимо поддерживать только открытый документированный интерфейс с типом.