Estou executando o StyleCop sobre algum código C # e ele continua relatando que minhas using
diretivas devem estar dentro do espaço para nome.
Existe uma razão técnica para colocar as using
diretivas dentro e não fora do espaço para nome?
c#
.net
namespaces
stylecop
code-organization
benPearce
fonte
fonte
using
declarações ; eles sãousing
diretrizes . Umausing
declaração, por outro lado, é uma estrutura de linguagem que ocorre junto com outras declarações dentro de um corpo de método etc. Como exemplo,using (var e = s.GetEnumerator()) { /* ... */ }
é uma declaração que é vagamente a mesma quevar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
declarações no interior dasnamespace
declarações, em suas guidlines codificação internosRespostas:
Na verdade, existe uma diferença (sutil) entre os dois. Imagine que você tenha o seguinte código em File1.cs:
Agora imagine que alguém adicione outro arquivo (File2.cs) ao projeto que se parece com isso:
O compilador pesquisa
Outer
antes de olhar para essasusing
diretivas fora do espaço para nome, para encontrar emOuter.Math
vez deSystem.Math
. Infelizmente (ou talvez felizmente?), NãoOuter.Math
temPI
membro, então o File1 está quebrado agora.Isso muda se você colocar
using
dentro da sua declaração de namespace, da seguinte maneira:Agora, o compilador pesquisa
System
antes de pesquisarOuter
, encontraSystem.Math
e está tudo bem.Alguns argumentam que
Math
pode ser um nome ruim para uma classe definida pelo usuário, já que já existe umaSystem
; o ponto aqui é apenas que há é a diferença, e isso afeta a manutenção do seu código.Também é interessante observar o que acontece se
Foo
estiver no espaço para nomeOuter
, e nãoOuter.Inner
. Nesse caso, a adiçãoOuter.Math
no Arquivo2 interrompe o Arquivo1, independentemente de para ondeusing
vai. Isso implica que o compilador pesquisa o espaço para nome mais interno antes de examinar qualquerusing
diretiva.fonte
Esse tópico já tem ótimas respostas, mas acho que posso trazer um pouco mais de detalhes com essa resposta adicional.
Primeiro, lembre-se de uma declaração de espaço para nome com pontos, como:
é inteiramente equivalente a:
Se você quisesse, poderia colocar
using
diretivas em todos esses níveis. (É claro que queremos terusing
s em apenas um lugar, mas seria legal de acordo com o idioma.)A regra para resolver qual tipo está implícito pode ser declarada de maneira vaga: Primeiro, procure uma correspondência correspondente no "escopo" mais interno; se nada for encontrado lá, vá um nível para o próximo escopo e procure lá, e assim por diante , até que uma correspondência seja encontrada. Se em algum nível mais de uma correspondência for encontrada, se um dos tipos pertencer à montagem atual, escolha essa e emita um aviso do compilador. Caso contrário, desista (erro em tempo de compilação).
Agora, vamos ser explícitos sobre o que isso significa em um exemplo concreto com as duas principais convenções.
(1) Com utilizações externas:
No caso acima, para descobrir qual
Ambiguous
é o tipo , a pesquisa segue nesta ordem:C
(incluindo tipos aninhados herdados)MyCorp.TheProduct.SomeModule.Utilities
MyCorp.TheProduct.SomeModule
MyCorp.TheProduct
MyCorp
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, eThirdParty
A outra convenção:
(2) Com usos dentro:
Agora, procure o tipo
Ambiguous
nesta ordem:C
(incluindo tipos aninhados herdados)MyCorp.TheProduct.SomeModule.Utilities
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, eThirdParty
MyCorp.TheProduct.SomeModule
MyCorp
(Observe que isso
MyCorp.TheProduct
fazia parte do "3." e, portanto, não era necessário entre "4." e "5.".)Observações finais
Não importa se você coloca as utilizações dentro ou fora da declaração do espaço para nome, sempre há a possibilidade de alguém posteriormente adicionar um novo tipo com nome idêntico a um dos espaços para nome com prioridade mais alta.
Além disso, se um espaço para nome aninhado tiver o mesmo nome que um tipo, poderá causar problemas.
É sempre perigoso mover os usos de um local para outro, porque a hierarquia de pesquisa é alterada e outro tipo pode ser encontrado. Portanto, escolha uma convenção e cumpra-a, para que você nunca precise mudar de uso.
Os modelos do Visual Studio, por padrão, colocam as utilizações fora do espaço para nome (por exemplo, se você fizer o VS gerar uma nova classe em um novo arquivo).
Uma (pequena) vantagem de ter utilizações externas é que você pode utilizar as diretivas de uso de um atributo global, por exemplo, em
[assembly: ComVisible(false)]
vez de[assembly: System.Runtime.InteropServices.ComVisible(false)]
.fonte
Colocá-lo dentro dos namespaces torna as declarações locais nesse namespace para o arquivo (caso você tenha vários namespaces no arquivo), mas se você tiver apenas um namespace por arquivo, não fará muita diferença se elas vão para fora ou dentro do espaço para nome.
fonte
using
diretivas dentro denamespace
blocos podem se referir a namespaces relativos com base nonamespace
bloco anexo .De acordo com Hanselman - Usando o carregamento de diretivas e montagens ... e outros artigos desse tipo, tecnicamente não há diferença.
Minha preferência é colocá-los fora dos espaços para nome.
fonte
My style is to put them outside the namespaces.
- apenas uma resposta em tudo.De acordo com a documentação do StyleCop:
SA1200: UsingDirectivesMustBePlacedWithinNamespace
Causa O AC # usando diretiva é colocado fora de um elemento de espaço para nome.
Descrição da regra Uma violação desta regra ocorre quando uma diretiva usando ou diretiva usando alias é colocada fora de um elemento do espaço para nome, a menos que o arquivo não contenha nenhum elemento do espaço para nome.
Por exemplo, o código a seguir resultaria em duas violações dessa regra.
O código a seguir, no entanto, não resultaria em nenhuma violação desta regra:
Esse código será compilado de maneira limpa, sem erros do compilador. No entanto, não está claro qual versão do tipo Guid está sendo alocada. Se a diretiva using for movida para dentro do namespace, como mostrado abaixo, ocorrerá um erro do compilador:
O código falha no seguinte erro do compilador, encontrado na linha que contém
Guid g = new Guid("hello");
CS0576: O espaço para nome 'Microsoft.Sample' contém uma definição em conflito com o alias 'Guid'
O código cria um alias para o tipo System.Guid chamado Guid e também cria seu próprio tipo chamado Guid com uma interface de construtor correspondente. Posteriormente, o código cria uma instância do tipo Guid. Para criar essa instância, o compilador deve escolher entre as duas definições diferentes do Guid. Quando a diretiva using-alias é colocada fora do elemento do espaço para nome, o compilador escolhe a definição local de Guid definida no espaço para nome local e ignora completamente a diretiva using-alias definida fora do espaço para nome. Infelizmente, isso não é óbvio ao ler o código.
Quando a diretiva using-alias é posicionada no espaço para nome, no entanto, o compilador deve escolher entre dois tipos de Guid diferentes e conflitantes, ambos definidos no mesmo espaço para nome. Ambos os tipos fornecem um construtor correspondente. O compilador não pode tomar uma decisão; portanto, sinaliza o erro do compilador.
Colocar a diretiva using-alias fora do namespace é uma prática ruim, pois pode causar confusão em situações como essa, nas quais não é óbvio qual versão do tipo está realmente sendo usada. Isso pode levar a um bug que pode ser difícil de diagnosticar.
A colocação de diretivas using-alias no elemento namespace elimina isso como uma fonte de bugs.
A colocação de vários elementos do espaço para nome em um único arquivo geralmente é uma má idéia, mas se e quando isso for feito, é uma boa idéia colocar todas as diretivas usando dentro de cada um dos elementos do espaço para nome, em vez de globalmente na parte superior do arquivo. Isso fará o escopo rigoroso dos espaços de nomes e também ajudará a evitar o tipo de comportamento descrito acima.
É importante observar que, quando o código foi escrito com o uso de diretivas colocadas fora do espaço para nome, deve-se tomar cuidado ao mover essas diretivas para dentro do espaço para nome, para garantir que isso não altere a semântica do código. Como explicado acima, a colocação de diretivas using-alias no elemento namespace permite que o compilador escolha entre tipos conflitantes de maneiras que não acontecerão quando as diretivas forem colocadas fora do namespace.
Como corrigir violações Para corrigir uma violação desta regra, mova todas as diretivas usando e alias usando o elemento de espaço para nome.
fonte
using
s fora do espaço para nome. Innerusing
s parece tão feio para mim. :)Há um problema com a colocação de instruções using dentro do namespace quando você deseja usar aliases. O alias não se beneficia das
using
declarações anteriores e deve ser totalmente qualificado.Considerar:
versus:
Isso pode ser particularmente pronunciado se você tiver um alias longo, como o seguinte (que foi como eu encontrei o problema):
Com
using
instruções dentro do espaço para nome, torna-se repentinamente:Feio.
fonte
class
precisa de um nome (identificador). Você não pode ter umausing
diretiva dentro de uma classe, como indica. Ele deve estar no nível do espaço para nome, por exemplo, fora da extremidade externanamespace
ou apenas dentro da parte internanamespace
(mas não dentro de uma classe / interface / etc.).using
diretrizes por engano. Eu editei para como eu pretendia que fosse. Obrigado por apontar. O raciocínio ainda é o mesmo.Como Jeppe Stig Nielsen disse , esse tópico já tem ótimas respostas, mas achei que essa sutileza bastante óbvia também merecia ser mencionada.
using
as diretivas especificadas dentro dos namespaces podem gerar um código mais curto, pois não precisam ser totalmente qualificadas como quando são especificadas externamente.O exemplo a seguir funciona porque os tipos
Foo
eBar
estão ambos no mesmo espaço para nome globalOuter
,.Suponha que o arquivo de código Foo.cs :
E Bar.cs :
Isso pode omitir o espaço para nome externo na
using
diretiva, para abreviar:fonte
Encontrei uma ruga (que não é abordada em outras respostas):
Suponha que você tenha esses espaços para nome:
Quando você usa
using Something.Other
fora de umnamespace Parent
, refere-se ao primeiro (Algo.Outro).No entanto, se você usá-lo dentro dessa declaração de namespace, ele se refere ao segundo (Parent.Something.Other)!
Existe uma solução simples: adicione o
global::
prefixo " ": docsfonte
As razões técnicas são discutidas nas respostas e acho que, no final, trata-se das preferências pessoais, já que a diferença não é tão grande e existem vantagens e desvantagens para as duas. O modelo padrão do Visual Studio para criar
.cs
arquivos usausing
diretivas fora dos espaços para nome, por exemploPode-se ajustar o stylecop para verificar as
using
diretivas fora dos namespaces, adicionando umstylecop.json
arquivo na raiz do arquivo do projeto com o seguinte:Você pode criar esse arquivo de configuração no nível da solução e adicioná-lo aos seus projetos como 'Arquivo de Link Existente' para compartilhar também a configuração em todos os seus projetos.
fonte
Outra sutileza que não acredito ter sido coberta por outras respostas é para quando você tem uma classe e um espaço para nome com o mesmo nome.
Quando você tiver a importação dentro do espaço para nome, ela encontrará a classe. Se a importação estiver fora do espaço para nome, a importação será ignorada e a classe e o espaço para nome deverão ser totalmente qualificados.
fonte
É uma prática recomendada se aqueles que usam o padrão "ie" " referências " na sua solução de origem estiverem fora dos espaços para nome e aqueles que são "nova referência adicionada" for uma boa prática, se você o colocar dentro do espaço para nome. Isso é para distinguir quais referências estão sendo adicionadas.
fonte