Доступность класса

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

Например, это даст ошибку: несогласованная доступность: базовый класс "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 вне его. Это может привести к ошибкам, если значение когда-либо изменилось.

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