#c_sharp #net
Часто замечаю код где библиотеки подключаются не перед namespace, а внутри. Интересно почему так делают и какие принципиальные различия? Привычный способ подключения: using System; using System.Linq; using System.Collections.Generic; namespace Domain { } Способ подключения внутри namespace: namespace Domain { using System; using System.Linq; using System.Collections.Generic; }
Ответы
Ответ 1
Перевод ответа на аналогичный вопрос на английском Разница действительно есть. Представим, что есть файл File1.cs со следующим кодом: // File1.cs using System; namespace Outer.Inner { class Foo { static void Bar() { double d = Math.PI; } } } Теперь представим, что кто-то добавил еще один файл (File2.cs): // File2.cs namespace Outer { class Math { } } Компилятор найдет Outer до того как просмотрит using вне пространства имен, поэтому он найдет Outer.Math вместо System.Math. К несчастью (или возможно к счастью?), в Outer.Math нет члена PI, поэтому компилятор начнет ругаться на Math.PI в файле File1.cs. Все поменяется, если поместить using внутрь определения пространства имен, например так: // File1b.cs namespace Outer.Inner { using System; class Foo { static void Bar() { double d = Math.PI; } } } Теперь компилятор найдет System до Outer, и будет использовать System.Math, и все будет хорошо. Некоторые утверждают, что Math это плохое имя для пользовательского класса, потому что такой класс уже есть в System; дело в том, что только здесь есть разница и это отразится на сопровождаемости кода. Также интересно, что может случиться, если Foo будет объявлен в пространстве именOuter, а не Outer.Inner. В этом случае, добавление Outer.Math в File2 ломает File1 независимо от того, где расположены using. Это означает, что компилятор ищет в самом внутреннем пространстве имен, прежде чем смотреть в любых выражениях using.Ответ 2
Перевод, одного из ответов Should 'using' statements be inside or outside the namespace? Для начала обратим внимание на тот факт, что пространство имен определенное вот таким образом: namespace MyCorp.TheProduct.SomeModule.Utilities { ... } эквивалентно определению нескольких вложенных пространств имен: namespace MyCorp { namespace TheProduct { namespace SomeModule { namespace Utilities { ... } } } } Если вы подключает сборку вне пространства, то она будет видна внутри всех охватывающих пространств. Правило поиска конкретного типа можно выразить примерно так: во-первых поиск совпадения в самой внутренней "области видимости", если ничего не нашли там выйти на один уровень вверх и искать там, и так далее, пока не будет найдено совпадение. Если на каком-то уровне встречается более чем одно совпадение, вы получите предупреждение компилятора. Если не найдено, выдать ошибку на этапе компиляции. Теперь, давайте более четко о том, что это означает, на конкретном примере с двумя основными конвенциями. (1) С usings снаружи: using System; using System.Collections.Generic; using System.Linq; //using MyCorp.TheProduct; <-- uncommenting this would change nothing using MyCorp.TheProduct.OtherModule; using MyCorp.TheProduct.OtherModule.Integration; using ThirdParty; namespace MyCorp.TheProduct.SomeModule.Utilities { class C { Ambiguous a; } } В приведенном случае, чтобы выяснить тип Ambiguous, поиск идет в следующем порядке: Вложенные типы внутри C (включая унаследованные вложенные типы) Типы в текущем пространстве имен MyCorp.TheProduct.SomeModule.Utilities Типы в пространстве имен MyCorp.TheProduct.SomeModule Типы в MyCorp.TheProduct Типы в MyCorp Типы в глобальном пространстве имен Типы в System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration и ThirdParty Другая конвенция: (2) С usings внутри: namespace MyCorp.TheProduct.SomeModule.Utilities { using System; using System.Collections.Generic; using System.Linq; using MyCorp.TheProduct; // MyCorp can be left out; this using is NOT redundant using MyCorp.TheProduct.OtherModule; // MyCorp.TheProduct can be left out using MyCorp.TheProduct.OtherModule.Integration; // MyCorp.TheProduct can be left out using ThirdParty; class C { Ambiguous a; } } Теперь поиск по типу Ambiguous идет в следующем порядке: Вложенные типы внутри C (включая унаследованные вложенные типы) Типы в текущем пространстве имен MyCorp.TheProduct.SomeModule.Utilities Типы в System, System.Collections.Generic, System.Linq, MyCorp.TheProduct , MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration и ThirdParty Типы в пространстве имен MyCorp.TheProduct.SomeModule Типы в MyCorp Типы в глобальном пространстве имен (Обратите внимание , что MyCorp.TheProduct был частью "3." и, следовательно , не требуется между "4." и "5".) Заключительные замечания Независимо от того, помещаете вы using внутри или вне объявления пространства имен, всегда есть вероятность того, что кто-то позже добавит новый тип с идентичным именем к одному из пространств, которое имеет более высокий приоритет. Кроме того, если вложенное пространство имен имеет то же имя, что и тип, это может вызвать проблемы. Всегда опасно перемещение using из одного места в другое, так как иерархия поиска изменяется, и может быть найден другой тип. Поэтому выберите одну конвенцию и придерживайтесь ее, что бы вам не пришлось когда-либо двигать using. Шаблоном Visual Studio, по умолчанию, является using вне пространства имен (например , если вы создате новый класс в новом файле). Одно (крошечное) преимущество наличия using вне пространства имен, вы можете использовать директивы для глобального атрибута, например [assembly: ComVisible(false)] вместо [assembly: System.Runtime.InteropServices.ComVisible(false)] .
Комментариев нет:
Отправить комментарий