Зачем использовать публичный метод во внутреннем классе? - PullRequest
222 голосов
/ 16 февраля 2012

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

internal static class Extensions
{
    public static string AddFoo(this string s)
    {
        if (!string.IsNullOrEmpty(s)) return s + "Foo";
        return "Foo";
    }
}

Есть ли какая-либо явная причина сделать это, кроме "проще сделать тип общедоступным позже?"

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

Ответы [ 10 ]

369 голосов
/ 16 февраля 2012

ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога в сентябре 2014 года . Спасибо за отличный вопрос!

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

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

Итак, теперь, учитывая внутренний класс, должны ли его члены, к которым вы хотите получить доступ в сборке, быть помечены как открытые или внутренние?

Мое мнение таково: отметьте таких участников как общедоступных.

Я использую «public» для обозначения «этот элемент не является деталью реализации». Защищенный элемент - это деталь реализации; в этом есть что-то, что понадобится, чтобы заставить производный класс работать. Внутренний член - это деталь реализации; что-то еще внутри этой сборки нуждается в члене для правильной работы. Публичный член говорит, что «этот член представляет ключевую, документированную функциональность, предоставляемую этим объектом».

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

Другие люди не согласны. Есть контингент, который говорит, что они хотят иметь возможность взглянуть на объявление члена и сразу узнать, будет ли он вызываться только из внутреннего кода.

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

14 голосов
/ 16 февраля 2012

Если класс internal, с точки зрения доступности не имеет значения, помечаете ли вы метод internal или public. Однако все еще хорошо использовать тип, который вы использовали бы, если бы класс был public.

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

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

10 голосов
/ 16 февраля 2012

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

8 голосов
/ 16 февраля 2012

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

Правила области видимости означают, что метод будет виден только как internal - поэтому действительно не имеет значения, помечены ли методы public или internal.

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

7 голосов
/ 16 февраля 2012

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

2 голосов
/ 16 февраля 2012

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

0 голосов
/ 19 апреля 2018

Я думаю, что у меня есть дополнительное мнение по этому поводу. Сначала мне было интересно, как имеет смысл объявить что-то публично во внутреннем классе. Затем я оказался здесь, читая, что было бы хорошо, если бы вы позже решили сменить класс на общедоступный. Правда. Итак, шаблон сформировался у меня в голове: Если он не меняет текущее поведение, то будьте терпеливы и допускайте вещи, которые не имеют смысла (и не причиняют вреда) в текущем состоянии код, но позже это произойдет, если вы измените объявление класса.

Как это:

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

В соответствии с "шаблоном", который я упомянул выше, это должно быть совершенно нормально. Это следует той же идее. Он ведет себя как метод private, так как вы не можете наследовать класс. Но если вы удалите ограничение sealed, оно остается в силе: унаследованные классы могут видеть этот метод, чего я и хотел достичь. Но вы получите предупреждение: CS0628 или CA1047. Они оба не объявляют protected членов в sealed классе. Более того, я нашел полное согласие, о том, что это бессмысленно: Предупреждение «Защищенный член в запечатанном классе» (одиночный класс)

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

0 голосов
/ 13 июня 2017

Разница есть.В нашем проекте мы сделали много внутренних классов, но мы проводим модульное тестирование в другой сборке, и в нашей информации о сборке мы использовали InternalsVisibleTo, чтобы позволить сборке UnitTest вызывать внутренние классы.Я заметил, что если во внутреннем классе есть внутренний конструктор, мы не можем по какой-то причине создать экземпляр с использованием Activator.CreateInstance в сборке модульного теста.Но если мы изменим конструктор на public, но класс все еще будет внутренним, он будет работать нормально.Но я предполагаю, что это очень редкий случай (как Эрик сказал в оригинальном сообщении: Отражение).

0 голосов
/ 26 мая 2015

Я действительно боролся с этим сегодня. До сих пор я бы сказал, что все методы должны быть помечены internal, если класс был internal, и считали бы что-либо еще просто плохим кодированием или ленью, особенно в развитии предприятия; тем не менее, я должен был создать подкласс public класса и переопределить один из его методов:

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

Метод ДОЛЖЕН быть public, и я подумал, что на самом деле нет логического смысла устанавливать методы как internal, если они действительно не должны быть, как сказал Эрик Липперт.

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

0 голосов
/ 16 февраля 2012

internal говорит, что доступ к элементу возможен только из одной сборки. Другие классы в этой сборке могут получить доступ к элементу internal public, но не смогут получить доступ к элементу private или protected, internal или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...