Зачем использовать открытый метод во внутреннем классе?

В одном из наших проектов есть много кода, который выглядит так:

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