Зачем использовать открытый метод во внутреннем классе?
В одном из наших проектов есть много кода, который выглядит так:
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (!string.IsNullOrEmpty(s)) return s + "Foo";
return "Foo";
}
}
Есть ли какая-либо явная причина для этого, кроме "проще сделать публикацию типа позже?"
Я подозреваю, что это имеет значение только в очень странных случаях кросс (отражение в Silverlight) или вообще нет.
Ответы
Ответ 1
ОБНОВЛЕНИЕ: этот вопрос был предметом моего блога в сентябре 2014 года. Спасибо за отличный вопрос!
Существует значительный спор по этому вопросу даже в самой команде компилятора.
Во-первых, разумно понять правила. Публичный член класса или структуры является членом, доступным для всего, что может получить доступ к содержащему типу. Таким образом, открытый член внутреннего класса является фактически внутренним.
Итак, теперь, учитывая внутренний класс, должны ли его члены, которые вы хотите получить доступ в сборке, отмечены как общедоступные или внутренние?
Мое мнение таково: отметьте таких членов как общедоступных.
Я использую "public" для обозначения "этот элемент не является детальностью реализации". Защищенный элемент представляет собой деталь реализации; есть что-то в этом, что понадобится, чтобы сделать производный класс работы. Внутренний элемент представляет собой деталь реализации; что-то другое внутри этой сборки нуждается в члене для правильной работы. Публичный член говорит, что "этот член представляет собой ключевую, документированную функциональность, предоставляемую этим объектом".
В принципе, мое отношение: предположим, я решил сделать этот внутренний класс открытым. Для этого я хочу изменить ровно одну вещь: доступность класса. Если превращение внутреннего класса в открытый класс означает, что я должен также превратить внутренний член в открытый член, тогда этот член был частью области публичной поверхности класса, и он должен был быть публичным в первую очередь.
Другие люди не согласны. Существует контингент, в котором говорится, что они хотят иметь возможность взглянуть на объявление участника и сразу же узнать, будет ли он вызван только из внутреннего кода.
К сожалению, это не всегда хорошо получается; например, внутренний класс, который реализует внутренний интерфейс, по-прежнему должен иметь элементы реализации, помеченные как общедоступные, потому что они являются частью открытой поверхности класса.
Ответ 2
Если класс internal
, с точки зрения доступности не имеет значения, отмечаете ли вы метод internal
или public
. Однако по-прежнему полезно использовать тип, который вы использовали бы, если класс был public
.
В то время как некоторые говорили, что это облегчает переходы от internal
до public
. Он также служит частью описания метода. Методы internal
обычно считаются небезопасными для неограниченного доступа, тогда как методы public
считаются (в основном) бесплатной игрой.
Используя internal
или public
, как и в классе public
, вы убедитесь, что вы сообщаете, какой стиль доступа ожидается, а также облегчает работу, необходимую для создания класса public
в будущее.
Ответ 3
Я часто отмечаю свои методы во внутренних классах public, а не в качестве внутреннего) a) это не имеет большого значения, и b) я использую internal, чтобы указать, что метод является внутренним по назначению (есть причина, по которой я не хочу чтобы разоблачить этот метод в открытом классе. Поэтому, если у меня есть внутренний метод, мне действительно нужно понять причину его внутреннего, прежде чем менять его на публичный, тогда как если я имею дело с общедоступным методом во внутреннем классе, мне действительно нужно думать о том, почему класс является внутренним, а не тем, почему каждый метод является внутренним.
Ответ 4
Я подозреваю, что "легче публиковать публикацию позже?" это.
Правила определения области видимости означают, что метод будет отображаться только как internal
- так что неважно, отмечены ли методы public
или internal
.
Одна возможность, которая приходит на ум, состоит в том, что класс был общедоступным и впоследствии был изменен на internal
, и разработчик не потрудился изменить все модификаторы доступности метода.
Ответ 5
В некоторых случаях также может быть, что внутренний тип реализует открытый интерфейс, что означает, что любые методы, определенные на этом интерфейсе, все равно должны быть объявлены публичными.
Ответ 6
То же самое, общедоступный метод будет по-прежнему помечен как внутренний, поскольку он находится внутри внутреннего класса, но имеет преимущество (по вашему мнению), если вы хотите пометить класс как общедоступный, вам нужно изменить меньшее количество кода.
Ответ 7
internal
говорит, что член может быть доступен только из одной сборки. Другие классы в этой сборке могут получить доступ к элементу internal public
, но не смогут получить доступ к элементу private
или protected
, internal
или нет.
Ответ 8
Я действительно боролся с этим сегодня. До сих пор я бы сказал, что все методы должны быть отмечены internal
, если класс был internal
и считал бы что-то еще просто плохим кодированием или лени, особенно в развитии предприятия; однако мне пришлось подкласс класса a public
и переопределить один из его методов:
internal class SslStreamEx : System.Net.Security.SslStream
{
public override void Close()
{
try
{
// Send close_notify manually
}
finally
{
base.Close();
}
}
}
Метод ДОЛЖЕН быть public
, и он заставил меня думать, что на самом деле нет логической точки для установки методов как internal
, если они действительно не должны быть, как сказал Эрик Липперт.
До сих пор я никогда не останавливался, чтобы думать об этом, я просто принял его, но, прочитав сообщение Эрика, это действительно заставило меня задуматься, и после того, как много размышлений, это имеет большой смысл.
Ответ 9
Есть разница.
В нашем проекте мы сделали много классов внутри, но мы делаем unit test в другой сборке, и в нашей сборке мы использовали InternalsVisibleTo, чтобы агрегат UnitTest вызывал внутренние классы.
Я заметил, что если внутренний класс имеет внутренний конструктор, мы не можем создать экземпляр, используя Activator.CreateInstance в сборке unit test по какой-либо причине. Но если мы изменим конструктор на публичный, но класс по-прежнему является внутренним, он отлично работает.
Но я думаю, что это очень редкий случай (как сказал Эрик в оригинальном посте: "Отражение" ).