Доступность класса
Почему в С# не допускается, чтобы производные классы имели большую доступность, чем его базовый класс.
Например, это даст ошибку: несогласованная доступность: базовый класс "BaseClass" менее доступен, чем класс "DerivedClass"
internal class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
И почему это разрешено в Java.
Ответы
Ответ 1
UPDATE. Этот вопрос был тема моего блога 13 ноября 2012 года. Спасибо за отличный вопрос!
Почему в С# не допускается, чтобы производные классы имели большую доступность, чем его базовый класс?
В дополнение к другим хорошим ответам рассмотрим этот сценарий. Вы и ваш коллега Алиса работаете на разных частях одной и той же сборки. Алиса пишет класс:
public class ComplicatedClass
{
public void DoDangerousThing() { ... }
}
Затем вы пишете
public class EvenMoreComplicatedClass : ComplicatedClass
{
}
Великий. Теперь Алиса получает обзор безопасности от Боба, и они понимают, что (1) никакой клиент никогда не должен использовать ComplicatedClass, и (2) DoDangerousThing раскрывает дыру в безопасности, которую мог бы использовать недружественный код. Внутреннего кода, конечно, нет.
Итак, Алиса меняет свой код на
internal class ComplicatedClass
{
public void DoDangerousThing() { ... }
}
Полагая, что нет необходимости изменять "общедоступный" на "внутренний" в методе, потому что, естественно, общественность означает "общедоступные вещи, которые могут видеть этот класс", и теперь никакой внешний код не может видеть этот класс.
Что произойдет с вашим кодом, когда Алиса перекомпилит с этим изменением? Он не должен компилировать. Вы сделали предположение, что пользователи должны видеть базовый класс, и Алиса внесла изменения, которые нарушают это предположение. Безопасное дело, чтобы компилятор сказал Алисе, что ей нужно поговорить с вами, чтобы вы могли решить эту проблему, не подвергая клиента уязвимости DoDangerousThing.
Почему это разрешено в Java?
Не знаю, извините.
Ответ 2
Таким образом, было бы тривиально использовать класс, помеченный как внутренний или закрытый, как если бы он был общедоступным, просто выполнив пустое переопределение, как и в вашем примере. Это нарушит цель маркировки классов вообще, чем вообще.
Ответ 3
internal
не совпадает с package private
в Java. Пользователь DerivedClass
может не иметь или иметь доступ к DLL, в котором BaseClass
находится в DerivedClass
, не может зависеть от него. Конфиденциальность пакетов - гораздо более легкая концепция в Java, но в вашем примере DerivedClass
должен быть в том же пакете, что и BaseClass
, поэтому у пользователя-клиента есть оба этих класса, чтобы Java позволял это.
Ответ 4
Потому что в противном случае вы будете подвергать членов BaseClass дальше, чем предполагалось.
Одним из примеров проблемы будет public const int Age
. Это нормально, потому что он доступен только в одной сборке, поэтому управление версиями безопасно. Если теперь вы используете наследование, чтобы сделать класс общедоступным, вы подвергаете это поле const вне его. Это может привести к ошибкам, если значение когда-либо изменилось.
Часто я делаю класс внутренним, так что мне не нужно так беспокоиться об управлении версиями его публичного интерфейса в будущем. Я могу изменить его в любое время и до тех пор, пока он собирается скомпилировать его, это нормально. Если кто-то пришел и обнародовал его публично, мне теперь пришлось бы повторно переустановить этот публичный интерфейс.