Практическое использование для «внутреннего» ключевого слова в C #

Не могли бы вы объяснить, какие практические примененияinternal ключевое слово в C #?

Я знаю чтоinternal Модификатор ограничивает доступ к текущей сборке, но когда мне это понадобится?

Ответы на вопрос(22)

конечно, ограниченным только сборкой, в которой он объявлен - получает "друг» функциональность в некоторой степени из этого. Друг друг - это то, что видно только определенным другим сборкам за пределами сборки, в которой он объявлен. C # не имеет встроенной поддержки для друга, однако CLR делает.

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

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

и над неуправляемым кодом.

Когда у вас есть библиотека на основе C / C ++, для которой вы хотите использовать DllImport, вы можете импортировать эти функции как статические функции класса и сделать их внутренними, чтобы у вашего пользователя был доступ только к вашей оболочке, а не к исходному API, чтобы он мог 'не связывайтесь ни с чем. Статические функции, которые вы можете использовать везде в сборке, для нескольких нужных вам классов-оболочек.

Вы можете взглянуть на Моно. Каир, этоs обертка вокруг библиотеки Каира, которая использует этот подход.

ет свои преимущества, например, упрощает понимание вашего API.

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

Мне нравится иметь инкапсуляцию на уровне класса и на уровне сборки. Есть те, кто не согласен с этим, но этоПриятно знать, что функциональность доступна.

который использует LINQ-to-SQL для данных конца. У меня есть два основных пространства имен: Biz и Data. Модель данных LINQ находится в Data и помеченавнутренний»; пространство имен Biz содержит открытые классы, которые обертывают классы данных LINQ.

Так что естьData.Client, а такжеBiz.Client; последний предоставляет все соответствующие свойства объекта данных, например:

private Data.Client _client;
public int Id { get { return _client.Id; } set { _client.Id = value; } }

У объектов Biz есть закрытый конструктор (для принудительного использования фабричных методов) и внутренний конструктор, который выглядит следующим образом:

internal Client(Data.Client client) {
    this._client = client;
}

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

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

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

Скажем, вы хотели, чтобы абстрактный класс был виден другой сборке, но вы неЯ не хочу, чтобы кто-то мог унаследовать это. Запечатанный выигралне работает, потому что этоПо какой-то причине, другие классы в этой сборке наследуются от него. Приват выигралне работает, потому что вы можете объявить родительский класс где-то в другой сборке.

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new ChildWithin();
    }
  }
}

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

то Бобу нужно заставить людей, которые владеют проектом A, зарегистрироваться, чтобы гарантировать, что BigImportantClass будет написан для удовлетворения его потребностей, протестирован, чтобы убедиться, что он соответствует его потребностям, задокументирован как удовлетворяющий его потребностям, и что процесс будет введен в действие, чтобы гарантировать, что он никогда не будет изменен, чтобы больше не отвечать его потребностям.

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

Дело не в том, что это усложняет жизнь Бобу. Это'Это означает, что он позволяет вам контролировать, какие дорогостоящие обещания дает Project A в отношении функций, срока службы, совместимости и так далее.

 Eric Lippert07 мая 2013 г., 16:56
@cwallenpoole: Если тыиспользовать код, написанный лжецами, которые пишут код, который вы незатем перестаньте использовать их код и напишите свой собственный, который вам больше нравится.
 cwallenpoole07 мая 2013 г., 17:10
@EricLippert Это должно было быть языком в щеке, я не хотел обидеть. (Я в основном просто пытался подтвердить, что я SOL в таких случаях).
 cwallenpoole07 мая 2013 г., 16:14
@EricLippert Не совсем то, что я имел в виду. Если я наследую скомпилированный код, который имеет "внутренний» в этом яЯ застрял, верно? Там'нельзя просто сказать компиляторуНет, этот другой разработчик солгал тебе. Ты должен доверять мне вместо этого если я не использую отражение.
 berniefitz29 янв. 2018 г., 23:09
Что, если Боб работал над проектом А?
 Eric Lippert07 мая 2013 г., 15:59
@cwallenpoole: Вы делаете. InternalsVisibleToAttribute.
 deadfish03 мая 2011 г., 19:42
Скажите, пожалуйста, как MSVS2010 узнает, какой из них (частный или внутренний) разумнее объявить новому классу?
 Eric Lippert07 мая 2013 г., 17:24
@cwallenpoole: яЯ не обижен ни в малейшей степени. Я'Я предлагаю хороший совет, если вы застряли в этой печальной ситуации.
 cwallenpoole07 мая 2013 г., 15:58
Имеет смысл. Просто хотелось бы, чтобы у нас была возможность переопределить внутренних членов, потому что мывсе согласные взрослые здесь.

Assembly1.cs и Assembly2.cs. Первый файл содержит внутренний базовый класс BaseClass. Во втором файле попытка создания экземпляра BaseClass приведет к ошибке.

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

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

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

источник:http://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx

обычно рекомендуется не предоставлять объект List внешним пользователям сборки, а предоставлять IEnumerable. Но намного проще использовать объект List внутри сборки, потому что вы получаете синтаксис массива и все другие методы List. Итак, у меня обычно есть внутреннее свойство, открывающее список для использования внутри сборки.

Приветствуются комментарии об этом подходе.

 Samik R21 апр. 2010 г., 17:29
@Howiecamp: В основном потому, что IEnumerable предоставляет доступ к списку только для чтения, где, как будто вы открываете список напрямую, он может быть изменен клиентами (например, удалить элементы и т. Д.), Что может быть непреднамеренным.
 Howiecamp21 апр. 2010 г., 05:23
@Samik - не могли бы вы уточнить, "Обычно рекомендуется не предоставлять объект List внешним пользователям сборки, а предоставлять IEnumerable. "  почему бесчисленное предпочтение?
 user56586904 мая 2011 г., 22:39
Кроме того, предоставление списка или IList создает контракт, который вы всегда разрешаете (например) быстрый произвольный доступ к данным. Если когда-нибудь вы решите изменить свой метод, чтобы использовать другую коллекцию или вообще не использовать коллекцию (возвращение дохода), вы 'Либо придется создать список только для того, чтобы вернуть значение, либо разорвать контракт, изменив тип возврата метода. Использование менее определенного типа возврата дает вам гибкость.
Решение Вопроса

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

ОтMSDN (через archive.org):

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

Вы также можете использовать внутренний модификатор вместе сInternalsVisibleTo Атрибут уровня сборки для создания "друг» сборки, которым предоставлен специальный доступ к внутренним классам целевой сборки.

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

 AD.Net28 нояб. 2018 г., 14:50
Я думаю, вам не нужно прибегать кinternal если вы определитеpublic интерфейсы ваших модулей хорошо. Каждый раз, когда я вижу обильное использованиеinternalДо сих пор они никогда не разочаровывали меня отсутствием кода спагетти.
 Scott Corbett12 февр. 2013 г., 22:35
В общем, я с тобой согласен. Единственное исключение - это возможность создавать модульные тесты без необходимости создавать частные средства доступа. Если вы хотите убедиться, что определенная зависимость была правильно назначена, а поле, содержащее эту зависимость, не является общедоступным, лучше использовать внутреннюю.
 KT.18 авг. 2016 г., 19:17
Иными словами, если все будут полагаться на внутреннюю часть SmtpClient, и в один момент там будет обнаружена ошибка, у .NET возникнут серьезные проблемы, чтобы исправить эту ошибку, возможно, даже удерживая ее в течение длительного времени. Помню, однажды я прочитал забавную статью, в которой описана длина, на которую разработчикам Windows приходилось идти, чтобы сохранитьсовместимость с ошибками " со всеми более старыми программами, которые использовали различные внутренние функции и ошибки. Повторять эту ошибку с .NET не имеет смысла.
 erict08 нояб. 2011 г., 22:11
Атрибут InternalsVisibleTo очень полезен. Спасибо.
 KT.07 июл. 2016 г., 13:52
@GrimaceofDespair: Позвольте мне добавить здесь комментарий. Я лично вижу внутреннюю как очень полезную версиюобщественности» модификатор в больших многопроектных решениях. Добавление этого модификатора к классу в моем подпроекте запрещает "случайное использование этого класса другими подпроектами в решении и позволяет мне принудительно использовать мою библиотеку. Если позже мне понадобится рефакторинг, я выиграюдолжен спросить себяподождите, но почему этот парень пошел и создал экземпляр класса Point, который мне был нужен только для моих собственных целей в этом конкретном вычислении "?
 Grimace of Despair18 окт. 2012 г., 14:32
Я чувствую, что с того момента, как вам нужно внутреннее,Что-то не так с дизайном где-то. ИМХО, нужно уметь использовать чистый ОО для решения всех проблем. В этот самый момент яЯ смотрю примерно на миллионное использование внутренних компонентов в .NET Framework, исключая мой способ использовать то, что они используют сами. Благодаря использованию внутренних, они создали монолит, который является поверхностно модульным, но разрушается, когда вы пытаетесь изолировать вещи. Кроме того, безопасность не является аргументом, так какОтражение на помощь.
 Nyerguds16 авг. 2016 г., 13:30
@KT. Чтобы не согласиться с вашим несогласием ... пользователи не могут делать какие-либо полезные подклассы, даже если сам класс технически можно разделить на подклассы, когда он использует 'внутренний»классы Я'Я в настоящее время ломаю голову над .Net v3.5 SmtpClient не отправляет "УВОЛИТЬСЯ" сообщение об отключении, с двумя слоямивнутренний» объекты на пути к его исправлению. (В некоторых корпоративных ситуациях обновление до более высоких версий фреймворка нет вариант).
 Nyerguds18 авг. 2016 г., 20:23
@KT. Да, у вас есть точка зрения, я думаю. Но я все еще думаю, что это очень часто блокирует больше, чем нужно.
 Darrell Plank02 дек. 2016 г., 18:53
Я думаю, что внутренний способ более полезен, чем публичный. Единственный раз, когда вы используете публичный, это когда вы явно говорите:Здесь пользователь - яЯ предоставляю вам полезную функцию ".  Если ты'при написании приложения, а не пользовательской библиотеки, все должно быть внутренним, потому что выМы не пытаемся дать людям какие-либо функции для внешнего вызова. Если ты'Если вы пишете пользовательскую библиотеку, тогда только те полезные функции, которые вы ожидаете предоставить пользователю, поддерживать, поддерживать и хранить до конца времени, должны быть общедоступными. В противном случае сделайте его внутренним.
 KT.18 авг. 2016 г., 19:12
@ Nyerguds, я до сих пор не думаю, что хакерские классы, которые разработчик отметил как внутренние, являются хорошим подходом здесь. Как только вы это сделаете, вы попадете в опасную зону, где иное совместимое обновление используемой вами библиотеки неожиданно и непредсказуемо сломает вашу систему. В вашем случае разумным подходом было бы скопировать предложения, которые вы хотите исправить, в свою собственную кодовую базу в качестве подмодуля и исправить их по своему вкусу, управляя внутренними компонентами по своему усмотрению. (Я предполагаю, что .NET-лицензия позволяет это, хотя яя не совсем уверен)

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

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

 R. Martinho Fernandes18 дек. 2009 г., 17:19
Если ты "использовать как можно более строгий модификатор тогда почему не приватно?
 Ilya Komakhin25 дек. 2009 г., 09:09
Поскольку private слишком строг, когда к свойствам / методам класса нужно обращаться за пределы класса, и в случаях, когда к ним нужно обращаться из другой сборки, bly встречается не так часто.

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

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

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

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

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

internal, Одним из примеров может быть, если вы хотите контролировать, как создаются экземпляры классов; позволять'скажем, вы предоставляете какую-то фабрику для создания экземпляров класса. Вы можете сделать конструкторinternal, так что фабрика (которая находится в той же сборке) может создавать экземпляры класса, но код вне этой сборки может:т.

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

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

public class DangerousClass {
    public void SafeMethod() { }
    internal void UpdateGlobalStateInSomeBizarreWay() { }
}
 pqsk06 сент. 2012 г., 14:54
Что ты пытаешься сказать? Это'не очень понятно. По крайней мере, не для меня.

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

оступа к конкретным реализациям со стороны пользователя вашей сборки.

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

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

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

Например, DAL может иметь ORM, но объекты не должны подвергаться бизнес-уровню, все взаимодействие должно осуществляться с помощью статических методов и передачи необходимых параметров.

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

Вероятно, изменится в будущих выпусках (если они будут общедоступными, вы нарушите код клиента)Бесполезны для клиента и могут привести к путаницеНе являются безопасными (поэтому неправильное использование может очень сильно сломать вашу библиотеку)

и т.п.

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

public будет автоматически отображаться в intellisense, когда кто-то смотрит на пространство имен вашего проекта. С точки зрения API важно показывать пользователям вашего проекта только те классы, которые они могут использовать. Использоватьinternal ключевое слово, чтобы скрыть то, что они не должныне вижу.

Если твойBig_Important_Class для проекта А предназначен для использования вне вашего проекта, то вы не должны отмечать его.internal

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

 Prisoner ZERO14 апр. 2011 г., 17:30
Так почему бы не использовать приват вместо этого?
 Matt Davis14 апр. 2011 г., 17:52
private Ключевое слово может использоваться только для классов или структур, которые определены в другом классе или структуре. Класс, определенный в пространстве имен, может быть объявлен толькоpublic или же .internal

что я когда-либо использовал ключевое слово internal - это код проверки лицензии в моем продукте ;-)

которая содержит множество сложных функций в простом общедоступном API, то «внутренний» используется для членов класса, которые не должны быть публично обнародованы.

Сокрытие сложности (например, инкапсуляция) является главной концепцией качественной разработки программного обеспечения.

чем меньше типов вы выставляете, тем проще ваша библиотека. Защита от несанкционированного вскрытия / безопасность - другое (хотя Reflection может победить это).

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

 Nyerguds16 авг. 2016 г., 13:38
Пфф. Глядя на байт-код с дизассемблером, вы все равно сможете понять, что делает код в любом случае. Обфускаторы едва ли являются мягким сдерживающим фактором для тех, кто действительно пытается проникнуть во внутренние органы. Никогда не слышал о хакере, который остановился только потому, что он неполучить полезные имена функций.
 Slothario08 окт. 2018 г., 20:55
Тот'Поэтому я шифрую имена классов и переменных в исходном коде. Возможно, вы сможете выяснить, что такое PumpStateComparator, но можете ли вы догадаться, что такое LpWj4mWE? #jobsecurity (я нене делайте этого, и, пожалуйста, нена самом деле, интернет-люди.)
 Sergio06 июл. 2017 г., 00:07
так что ты нене запирай дверь, когда спишь, потому что тыникогда не слышал о воре, остановленном замком?

Ваш ответ на вопрос