В одном из наших проектов много кода, который выглядит следующим образом:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (s == null)
{
return "Foo";
}
return $({s}Foo);
}
}
Есть ли какая-либо явная причина, чтобы сделать это, кроме как «легче сделать тип общедоступным позже?»
Я подозреваю, что это имеет значение только в очень странных крайних случаях (отражение в Silverlight) или вообще не имеет значения.
return s + "Foo";
?+
Оператор не заботится о нулевых или пустых строках.Ответы:
ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога в сентябре 2014 года . Спасибо за отличный вопрос!
По этому вопросу ведутся серьезные дебаты даже внутри самой команды разработчиков.
Во-первых, разумно понимать правила. Открытый член класса или структуры - это член, который доступен любому, кто может получить доступ к содержащему типу . Таким образом, открытый член внутреннего класса фактически является внутренним.
Итак, теперь, учитывая внутренний класс, должны ли его члены, к которым вы хотите получить доступ в сборке, быть помечены как открытые или внутренние?
Мое мнение таково: отметьте таких участников как общедоступных.
Я использую «public» для обозначения «этот элемент не является деталью реализации». Защищенный элемент - это деталь реализации; в этом есть что-то, что понадобится, чтобы заставить производный класс работать. Внутренний член - это деталь реализации; что-то еще внутри этой сборки нуждается в члене для правильной работы. Публичный член говорит, что «этот член представляет ключевую, документированную функциональность, предоставляемую этим объектом».
По сути, мое отношение таково: предположим, я решил превратить этот внутренний класс в публичный класс. Чтобы сделать это, я хочу изменить только одну вещь : доступность класса. Если превращение внутреннего класса в публичный класс означает, что я должен также превратить внутренний член в публичный, то этот член был частью публичной области класса, и он должен был быть в первую очередь публичным.
Другие люди не согласны. Есть контингент, который говорит, что они хотят иметь возможность взглянуть на объявление члена и сразу узнать, будет ли он вызываться только из внутреннего кода.
К сожалению, это не всегда хорошо получается; например, внутренний класс, который реализует внутренний интерфейс, все еще должен иметь члены реализации, помеченные как публичные, потому что они являются частью общедоступной поверхности класса .
источник
public
очень убедителен. Тем не менее, я считаю, что "не всегда хорошо получается", чтобы быть особенно мощным. Потеря последовательности обесценивает любые «краткие» преимущества. Использованиеinternal
таким образом означает намеренное построение интуиции, которая иногда ошибочна. IMO - это правильная интуиция - ужасная вещь для программирования.Если класс есть
internal
, с точки зрения доступности не имеет значения, помечаете ли вы методinternal
илиpublic
. Однако все еще хорошо использовать тип, который вы использовали бы, если бы класс былpublic
.Хотя некоторые говорят, что это облегчает переходы от
internal
кpublic
. Он также служит частью описания метода.Internal
методы обычно считаются небезопасными для беспрепятственного доступа, в то время какpublic
методы считаются (в основном) бесплатной игрой.Используя
internal
илиpublic
как вpublic
классе, вы гарантируете, что сообщаете, какой стиль доступа ожидается, одновременно упрощая работу, необходимую для создания классаpublic
в будущем.источник
Я часто отмечаю свои методы во внутренних классах как открытые, а не внутренние как: а) это на самом деле не имеет значения и б) я использую внутренний, чтобы указать, что метод является внутренним для намерения (есть некоторая причина, почему я не хочу раскрывать это Метод в публичном классе. Поэтому, если у меня есть внутренний метод, я действительно должен понять причину, по которой он является внутренним, прежде чем менять его на публичный, тогда как если я имею дело с публичным методом во внутреннем классе, мне действительно нужно подумать, почему Класс является внутренним, в отличие от того, почему каждый метод является внутренним.
источник
Я подозреваю, что "легче сделать тип позже публичным?" это.
Правила области видимости означают, что метод будет виден только как
internal
- так что на самом деле не имеет значения, помечены ли методыpublic
илиinternal
.Одна возможность, которая приходит на ум, заключается в том, что класс был общедоступным, а затем был изменен на,
internal
и разработчик не удосужился изменить все модификаторы доступности метода.источник
В некоторых случаях может также оказаться, что внутренний тип реализует открытый интерфейс, что будет означать, что любые методы, определенные в этом интерфейсе, все равно должны быть объявлены как открытые.
источник
То же самое, публичный метод будет действительно помечен как внутренний, так как он находится внутри внутреннего класса, но у него есть преимущество (как вы уже догадались): если вы хотите пометить класс как открытый, вы должны изменить меньше кода.
источник
internal
говорит, что к члену можно получить доступ только из одной сборки. Другие классы в этой сборке могут получить доступ кinternal public
члену, но не смогут получить доступ к членуprivate
илиprotected
члену,internal
или нет.источник
internal
вместо них были отмечены методыpublic
, их видимость не изменилась бы. Я считаю, что это то, о чем спрашивает ОП.Я на самом деле боролся с этим сегодня. До сих пор я бы сказал, что все методы должны быть помечены,
internal
если бы класс былinternal
и считал бы что-либо еще просто плохим кодированием или ленью, особенно в развитии предприятия; Тем не менее, я должен был подкласс классаpublic
и переопределить один из его методов:Метод ДОЛЖЕН быть,
public
и это заставило меня задуматься о том, что на самом деле нет логического смысла в установке методов,internal
если только они не должны быть, как сказал Эрик Липперт.До сих пор я никогда не задумывался об этом, я просто принял это, но после прочтения поста Эрика это действительно заставило меня задуматься, и после долгих размышлений это имеет большой смысл.
источник
Там есть разница. В нашем проекте мы сделали много внутренних классов, но мы проводим модульное тестирование в другой сборке, и в нашей информации о сборке мы использовали InternalsVisibleTo, чтобы позволить сборке UnitTest вызывать внутренние классы. Я заметил, что если во внутреннем классе есть внутренний конструктор, мы не можем по какой-то причине создать экземпляр с использованием Activator.CreateInstance в сборке модульного теста. Но если мы изменим конструктор на public, но класс все еще будет внутренним, он будет работать нормально. Но я думаю, что это очень редкий случай (как сказал Эрик в оригинальном сообщении: «Отражение»).
источник
Я думаю, что у меня есть дополнительное мнение по этому вопросу. Сначала мне было интересно, как имеет смысл объявить что-то публично во внутреннем классе. Затем я оказался здесь, читая, что было бы хорошо, если бы вы позже решили сменить класс на общедоступный. Правда. Итак, шаблон сформировался у меня в голове: если он не меняет текущее поведение, то будьте терпеливы и допускайте вещи, которые не имеют смысла (и не причиняют вреда) в текущем состоянии кода, но позже это будет, если вы изменить объявление класса.
Как это:
В соответствии с «шаблоном», который я упомянул выше, это должно быть совершенно нормально. Это следует той же идее. Он ведет себя как
private
метод, так как вы не можете наследовать класс. Но если вы удалитеsealed
ограничение, оно все равно будет действительным: унаследованные классы могут видеть этот метод, чего я и хотел достичь. Но вы получаете предупреждение:CS0628
илиCA1047
. Они оба не объявляютprotected
членов вsealed
классе. Более того, я нашел полное согласие, о том, что это бессмысленно: предупреждение «Защищенный член в запечатанном классе» (одиночный класс)Поэтому после того, как это предупреждение и дискуссия были связаны, я решил сделать все внутренним или менее внутренним, потому что оно больше соответствует такому мышлению, и мы не смешиваем разные «шаблоны».
источник