Почему С# не поддерживает пересечение защищенной и внутренней доступности? - программирование
Подтвердить что ты не робот

Почему С# не поддерживает пересечение защищенной и внутренней доступности?

защищенный внутренний:

Объединение защищенной и внутренней доступности (это менее ограничительный, чем защищенный или внутренний)

CLR имеет концепцию пересечения защищенной и внутренней доступности, но С# не поддерживает это.

Итак, мой вопрос:

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

4b9b3361

Ответ 1

Обновление: С# 7.2 представляет это с помощью модификатора доступа private protected, который кажется неправильным несколькими способами, но не позволяет избежать значительной возможности для путаницы, которую я описываю ниже, так что, возможно, это лучший из плохой группы.

Лично я хотел этого довольно много раз. Бывают случаи, когда один из них предоставляет класс и один или несколько классов, полученных из него как public в сборке, и бывают случаи, когда некоторый член базового класса используется только этими производными классами и не должен подвергаться защищенным классам в других сборках (нередко это конструктор, чтобы другие сборки не имели классов, которые вообще выходят из него).

Конечно, всегда полезно определить ваш доступ как можно более ограничительным, и поэтому пересечение защищенного и внутреннего - именно то, что здесь нужно.

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

Однако рассмотрим недостаток.

Как бы там ни было, существует некоторая путаница в том, как protected internal дает объединение protected и internal. Это, вероятно, самый непонятый доступ, судя по вопросам на таких сайтах.

Что мы можем назвать? internal protected? Можете ли вы представить, как часто люди путаются с protected internal? Нам нужно что-то более четко дифференцированное, и мы хотели бы того же для internal protected (потому что мы все еще увеличили его потенциал для путаницы). Это не проблема, на которую невозможно ответить, но сохранение количества ключевых слов также является хорошей идеей.

Даже если найдется идеальный ответ на вопрос об именах, потенциальная путаница, введя еще один уровень доступа, не полностью побеждена.

Итак, имея в виду, пусть снова посмотрит вверх. Нам больше не нужно удалять время, в котором мы нуждаемся, используя internal, уменьшая ошибки, вызванные ненадлежащим использованием такого члена. Хорошо, как часто это происходит, и насколько вероятны такие ошибки на самом деле? Не очень часто, и не очень вероятно.

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

Ответ 2

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

Таким образом, единственным преимуществом a protected internal intersection будет то, что вы будете дисциплинировать себя, как разработчика вашей библиотеки, чтобы не получать доступ к типу/члену, кроме одного и того же или производного классов в вашей библиотеке. Это не будет иметь никакого значения для потребителей вашей библиотеки, поскольку его семантика будет идентична простой internal.

Тем не менее, я бы не счел это необоснованным для его разрешения на С#. Самодисциплина часто оказывается полезной; это причина, по которой разработчики языка отличались между private и internal, несмотря на то, что они были идентичными для внешних потребителей.

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

Ответ 3

Это было дизайнерское решение, но подумайте, что это значит:

  • доступен только для производных классов в той же сборке.

Это не очень полезная граница, я не могу придумать явный пример использования.
И почему это, вероятно, не стоило придумывать новое ключевое слово (-комбинация).

Я бы предпочел спросить, почему CLR поддерживает его. Я полагаю, ортогональность.

Ответ 4

Итак, почему С# не должен его поддерживать?

Неверный вопрос. Вопрос должен быть "зачем С# поддерживать protected and internal?"

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

В частности, каково значение protected and internal? Нет оснований для ограничения доступа только к производным классам в той же сборке.

ИМО это странно, CLR поддерживает его, но это так. Это не означает, что С# должен быть.

Ответ 5

Я хотел задать этот же вопрос, но, к счастью, SO нашел это для меня.

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

Тем не менее, я задаюсь вопросом, является ли законным избегать реализации этой функции CLR из-за узкого варианта использования или потому, что это может смутить людей.

Один из приведенных выше аргументов состоит в том, что он будет использовать только самодисциплину.

Но то же самое можно сказать о любом модификаторе видимости, который не является public. Идея также в том, что она применима только к "одному разработчику одной библиотеки", также явно ошибочна. Многие библиотеки разрабатываются группами людей, и совершенно естественно, что разработчик в этой команде может добавить члена, который он или она хотел бы ограничить только внутренними типами, полученными из его или ее базы.

Тогда существует такой сценарий:

internal class Foo {

}

public class PublicBase {
  protected Foo MyFoo { get; set; }
}

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

В этой ситуации я застрял: я не могу использовать protected, и я не могу использовать protected internal.

Вместо этого я должен использовать internal, который неправильно передает другим членам моей команды, что он должен использоваться из кода вне класса. Конечно, я могу прокомментировать его (и даже наклеить на него EditorBrowsableAttribute of Never, но это тоже скроет его от внутренних наследователей), но это не то же самое.

Как бы то ни было, единственный способ добиться этого - взломать сборку с помощью перезаписи IL после сборки, но мне нужна эта видимость (или ее отсутствие) во время компиляции, а не после ее создания.

В конечном счете, аргументы о том, "какое ключевое слово (и) он использовал бы" или "как это будет реализовано", не имеют отношения ко мне: я программист, а не разработчик языка С#.

В равной степени я должен сказать, что такие аргументы, как "Ну, protected internal достаточно запутывает для многих", также не имеют значения. Есть так много разработчиков, с которыми я столкнулся, лично или практически, кто не понимает такие вещи, как ?: или общие ограничения - угадайте, что они не используют их! Это не значит, что я не должен.

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

И да, я готов к жаре, которая может привести к моей двери:)

Ответ 6

Насколько я знаю, вы можете использовать пересечение защищенных и внутренних модификаторов доступа, но не с необходимой интерпретацией (возможно, из-за того, что сказал Хенк):

  • Защищено: к типу или члену может обращаться только код в том же классе или структуре или в производном классе.

  • Внутренний: к типу или члену можно получить доступ любым кодом в той же сборке, но не с другой сборки.

  • Защищенный внутренний: к типу или члену можно получить доступ любым кодом в той же сборке или любым производным классом в другой сборке.

Ответ 7

Вы всегда можете сделать:

public MyExternallySealedClass
{
     internal MyExternallySealedClass() {...}

     ...
}

Пока вы не позволяете любому внешнему пользователю создавать экземпляр объекта, что вам небезразлично, если он попытается получить его? Короткий ответ, функция, которую вы запрашиваете, не приносит ничего нового, и у вас уже есть инструменты для выполнения того, что вы запрашиваете.