Я запускал StyleCop над кодом C #, и он продолжает сообщать, что мои using
директивы должны быть внутри пространства имен.
Есть ли техническая причина для размещения using
директив внутри, а не вне пространства имен?
c#
.net
namespaces
stylecop
code-organization
benPearce
источник
источник
using
заявления ; они являютсяusing
директивами . Сusing
другой стороны, оператор - это языковая структура, которая встречается вместе с другими операторами внутри тела метода и т. Д. В качестве примера можно привестиusing (var e = s.GetEnumerator()) { /* ... */ }
оператор, который в значительной степени совпадает сvar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
операторы вnamespace
декларации, в их внутренниеОтветы:
На самом деле есть (тонкая) разница между ними. Представьте, что у вас есть следующий код в File1.cs:
Теперь представьте, что кто-то добавляет в проект другой файл (File2.cs), который выглядит следующим образом:
Компилятор ищет,
Outer
прежде чем смотреть на этиusing
директивы вне пространства имен, поэтому он находитOuter.Math
вместоSystem.Math
. К сожалению (или, возможно, к счастью?),Outer.Math
НетPI
члена, поэтому File1 теперь не работает.Это изменится, если вы поместите
using
внутреннюю декларацию пространства имен следующим образом:Теперь компилятор ищет
System
перед поискомOuter
, находитSystem.Math
, и все хорошо.Некоторые утверждают, что это
Math
может быть плохое имя для пользовательского класса, поскольку он уже естьSystem
; Дело здесь только в том, что есть разница, и это влияет на удобство сопровождения вашего кода.Также интересно отметить, что происходит, если
Foo
находится в пространстве именOuter
, а неOuter.Inner
. В этом случае добавлениеOuter.Math
в File2 нарушает работу File1 независимо от того, куда онusing
идет. Это подразумевает, что компилятор ищет самое внутреннее пространство имен, прежде чем он смотрит на любуюusing
директиву.источник
В этой теме уже есть несколько отличных ответов, но я чувствую, что могу добавить немного больше подробностей с этим дополнительным ответом.
Во-первых, помните, что объявление пространства имен с точками, например:
полностью эквивалентно:
Если вы хотите, вы можете поместить
using
директивы на всех этих уровнях. (Конечно, мы хотим иметьusing
s только в одном месте, но это будет законно в зависимости от языка.)Правило для определения того, какой тип подразумевается, можно условно сформулировать следующим образом: сначала ищите самую внутреннюю «область» для совпадения, если там ничего не найдено, переходите на один уровень к следующей области и ищите там, и так далее , пока совпадение не найдено. Если на каком-то уровне найдено более одного совпадения, если один из типов относится к текущей сборке, выберите его и выдайте предупреждение компилятора. В противном случае сдавайтесь (ошибка времени компиляции).
Теперь давайте подробно рассмотрим, что это значит в конкретном примере с двумя основными соглашениями.
(1) с использованием снаружи:
В приведенном выше случае, чтобы узнать, какой тип
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) с использованием внутри:
Теперь поиск по типу
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».)Заключительные замечания
Независимо от того, помещаете ли вы использование внутри или вне объявления пространства имен, всегда есть вероятность, что кто-то позже добавит новый тип с идентичным именем в одно из пространств имен, которые имеют более высокий приоритет.
Кроме того, если вложенное пространство имен имеет то же имя, что и тип, это может вызвать проблемы.
Всегда опасно перемещать данные из одного места в другое, потому что меняется иерархия поиска, и может быть найден другой тип. Поэтому выберите одно соглашение и придерживайтесь его, чтобы вам никогда не приходилось переносить обычаи.
Шаблоны Visual Studio по умолчанию помещают значения за пределы пространства имен (например, если вы заставляете VS генерировать новый класс в новом файле).
Одним (крошечным) преимуществом использования извне является то, что вы можете использовать директивы using для глобального атрибута, например,
[assembly: ComVisible(false)]
вместо[assembly: System.Runtime.InteropServices.ComVisible(false)]
.источник
Помещение его в пространства имен делает объявления локальными для этого пространства имен для файла (в случае, если у вас есть несколько пространств имен в файле), но если у вас есть только одно пространство имен на файл, тогда не имеет большого значения, выходят ли они наружу или внутри пространства имен.
источник
using
Директивы внутриnamespace
блоков могут ссылаться на относительные пространства имен, основанные на включающемnamespace
блоке.Согласно Hanselman - Использование директивы и сборки Загрузка ... и другие подобные статьи, технически нет никакой разницы.
Я предпочитаю размещать их вне пространства имен.
источник
My style is to put them outside the namespaces.
- едва ли ответ на все.Согласно документации StyleCop:
SA1200: использованиеDirectivesMustBePlacedWithinNamespace
Причина. Директива AC # using размещена вне элемента пространства имен.
Описание правила Нарушение этого правила происходит, когда директива using или директива using-alias размещаются вне элемента пространства имен, если файл не содержит никаких элементов пространства имен.
Например, следующий код приведет к двум нарушениям этого правила.
Однако следующий код не приведет к каким-либо нарушениям этого правила:
Этот код будет компилироваться без ошибок компилятора. Однако неясно, какая версия типа Guid выделяется. Если директива using перемещается внутри пространства имен, как показано ниже, произойдет ошибка компилятора:
Сбой кода при следующей ошибке компилятора, найденной в строке, содержащей
Guid g = new Guid("hello");
CS0576: пространство имен «Microsoft.Sample» содержит определение, конфликтующее с псевдонимом «Guid»
Код создает псевдоним для типа System.Guid с именем Guid, а также создает свой собственный тип с именем Guid с соответствующим интерфейсом конструктора. Позже код создает экземпляр типа Guid. Чтобы создать этот экземпляр, компилятор должен выбрать между двумя различными определениями Guid. Когда директива using-alias размещается вне элемента пространства имен, компилятор выбирает локальное определение Guid, определенное в локальном пространстве имен, и полностью игнорирует директиву using-alias, определенную вне пространства имен. Это, к сожалению, неочевидно при чтении кода.
Однако, когда директива using-alias размещается в пространстве имен, компилятору приходится выбирать между двумя различными, конфликтующими типами Guid, оба определены в одном и том же пространстве имен. Оба эти типа предоставляют соответствующий конструктор. Компилятор не может принять решение, поэтому он отмечает ошибку компилятора.
Размещение директивы using-alias вне пространства имен является плохой практикой, поскольку это может привести к путанице в ситуациях, подобных этой, когда неясно, какая версия типа фактически используется. Это может привести к ошибке, которую сложно диагностировать.
Размещение директив using-alias в элементе namespace устраняет это как источник ошибок.
Размещение нескольких элементов пространства имен в одном файле, как правило, является плохой идеей, но если и когда это будет сделано, будет хорошей идеей поместить все использующие директивы в каждый из элементов пространства имен, а не глобально в верхней части файла. Это будет ограничивать пространства имен, а также поможет избежать поведения, описанного выше.
Важно отметить, что, когда код был написан с использованием директив, размещенных вне пространства имен, следует соблюдать осторожность при перемещении этих директив в пространстве имен, чтобы гарантировать, что это не изменит семантику кода. Как объяснялось выше, размещение директив using-alias в элементе пространства имен позволяет компилятору выбирать между конфликтующими типами таким образом, чтобы этого не происходило, если директивы размещаются вне пространства имен.
Как исправить нарушения Чтобы исправить нарушение этого правила, переместите все с использованием директив и директив using-alias в элемент пространства имен.
источник
using
s вне пространства имен. Innerusing
s выглядит так безобразно для меня. :)Существует проблема с размещением операторов using в пространстве имен, когда вы хотите использовать псевдонимы. Псевдоним не извлекает выгоду из предыдущих
using
заявлений и должен быть полностью квалифицированным.Рассматривать:
против:
Это может быть особенно заметно, если у вас есть длинный псевдоним, такой как следующий (вот как я нашел проблему):
С
using
заявлениями внутри пространства имен это внезапно становится:Не красиво
источник
class
нужно имя (идентификатор). Вы не можете иметьusing
директиву внутри класса, как вы указываете. Он должен быть на уровне пространства имен, например, снаружи самого внешнегоnamespace
или только внутри самого внутреннегоnamespace
(но не внутри класса / интерфейса / и т. Д.).using
ошибочно расставил директивы. Я отредактировал его так, как задумал. Спасибо за указание. Однако рассуждения все те же.Как сказал Джепп Стиг Нильсен , у этой ветки уже есть отличные ответы, но я подумал, что эту довольно очевидную тонкость тоже стоит упомянуть.
using
Директивы, указанные внутри пространств имен, могут привести к сокращению кода, поскольку они не должны быть полностью квалифицированными, как если бы они были указаны снаружи.Следующий пример работает, потому что типы
Foo
иBar
оба находятся в одном глобальном пространстве именOuter
.Предположим, файл кода Foo.cs :
И Bar.cs :
Это может опустить внешнее пространство имен в
using
директиве, для краткости:источник
Одна морщина, с которой я столкнулся (это не покрыто другими ответами):
Предположим, у вас есть эти пространства имен:
При использовании
using Something.Other
снаружи отnamespace Parent
, это относится к первому (Something.Other).Однако, если вы используете его внутри этого объявления пространства имен, оно ссылается на второе (Parent.Something.Other)!
Есть простое решение: добавить
global::
префикс " ": docsисточник
Технические причины обсуждаются в ответах , и я думаю , что речь идет о личных предпочтениях в конце концов , так как разница не так уж большая , и есть компромиссы для обоих из них. Шаблон Visual Studio по умолчанию для создания
.cs
файлов используетusing
директивы вне пространств имен, напримерМожно настроить stylecop для проверки
using
директив вне пространств имен, добавивstylecop.json
файл в корень файла проекта с помощью следующего:Вы можете создать этот файл конфигурации на уровне решения и добавить его в свои проекты как «Существующий файл ссылок», чтобы разделить конфигурацию также со всеми вашими проектами.
источник
Другая тонкость, которую я не верю, была покрыта другими ответами для случая, когда у вас есть класс и пространство имен с тем же именем.
Когда у вас есть импорт внутри пространства имен, он найдет класс. Если импорт находится за пределами пространства имен, то импорт будет проигнорирован, а класс и пространство имен должны быть полностью квалифицированы.
источник
Рекомендуется, чтобы те, по умолчанию использующие, например, « ссылки », используемые в исходном решении, находились за пределами пространств имен, а те, которые являются «новой добавленной ссылкой», - это хорошая практика, если вы должны поместить его в пространство имен. Это должно отличить, какие ссылки добавляются.
источник