He estado ejecutando StyleCop sobre algún código C #, y sigue informando que mis using
directivas deben estar dentro del espacio de nombres.
¿Hay alguna razón técnica para colocar las using
directivas dentro en lugar de fuera del espacio de nombres?
c#
.net
namespaces
stylecop
code-organization
benPearce
fuente
fuente
using
declaraciones ; Sonusing
directivas . Unausing
declaración, por otro lado, es una estructura de lenguaje que ocurre junto con otras declaraciones dentro del cuerpo de un método, etc. Como ejemplo,using (var e = s.GetEnumerator()) { /* ... */ }
es una declaración que es más o menos igual quevar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
declaraciones dentro de lasnamespace
declaraciones, en susRespuestas:
En realidad, hay una diferencia (sutil) entre los dos. Imagine que tiene el siguiente código en File1.cs:
Ahora imagine que alguien agrega otro archivo (File2.cs) al proyecto que se ve así:
El compilador busca
Outer
antes de mirar esasusing
directivas fuera del espacio de nombres, por lo que encuentra enOuter.Math
lugar deSystem.Math
. Desafortunadamente (¿o quizás afortunadamente?), NoOuter.Math
tiene ningúnPI
miembro, por lo que File1 ahora está roto.Esto cambia si coloca
using
dentro de su declaración de espacio de nombres, de la siguiente manera:Ahora el compilador busca
System
antes de buscarOuter
, encuentraSystem.Math
y todo está bien.Algunos argumentarían que
Math
podría ser un mal nombre para una clase definida por el usuario, ya que ya hay unaSystem
; El punto aquí es que no es una diferencia, y que afecta a la capacidad de mantenimiento de su código.También es interesante observar lo que sucede si
Foo
está en el espacio de nombresOuter
, en lugar de hacerloOuter.Inner
. En ese caso, agregarOuter.Math
File2 rompe File1 independientemente de dóndeusing
vaya. Esto implica que el compilador busca el espacio de nombres que lo encierra más interno antes de mirar cualquierusing
directiva.fuente
Este hilo ya tiene algunas respuestas geniales, pero creo que puedo aportar un poco más de detalle con esta respuesta adicional.
Primero, recuerde que una declaración de espacio de nombres con puntos, como:
es completamente equivalente a:
Si quisieras, podrías poner
using
directivas en todos estos niveles. (Por supuesto, queremos tenerusing
s en un solo lugar, pero sería legal según el idioma).La regla para resolver qué tipo está implícito, se puede expresar de manera general de esta manera: primero busque una "coincidencia" más interna para una coincidencia, si no se encuentra nada, salga un nivel al siguiente alcance y busque allí, y así sucesivamente , hasta que se encuentre una coincidencia. Si en algún nivel se encuentra más de una coincidencia, si uno de los tipos es del ensamblaje actual, elíjalo y emita una advertencia de compilación. De lo contrario, renunciar (error en tiempo de compilación).
Ahora, seamos explícitos sobre lo que esto significa en un ejemplo concreto con las dos convenciones principales.
(1) Con usos fuera:
En el caso anterior, para averiguar qué tipo
Ambiguous
es, la búsqueda va en este orden:C
(incluidos los tipos anidados heredados)MyCorp.TheProduct.SomeModule.Utilities
MyCorp.TheProduct.SomeModule
MyCorp.TheProduct
MyCorp
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, yThirdParty
La otra convención:
(2) Con usos dentro:
Ahora, busque el tipo
Ambiguous
en este orden:C
(incluidos los tipos anidados heredados)MyCorp.TheProduct.SomeModule.Utilities
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, yThirdParty
MyCorp.TheProduct.SomeModule
MyCorp
(Tenga en cuenta que
MyCorp.TheProduct
era parte de "3." y, por lo tanto, no era necesario entre "4." y "5.").Observaciones finales
No importa si coloca los usos dentro o fuera de la declaración del espacio de nombres, siempre existe la posibilidad de que alguien luego agregue un nuevo tipo con un nombre idéntico a uno de los espacios de nombres que tienen mayor prioridad.
Además, si un espacio de nombres anidado tiene el mismo nombre que un tipo, puede causar problemas.
Siempre es peligroso mover los usos de una ubicación a otra porque la jerarquía de búsqueda cambia y se puede encontrar otro tipo. Por lo tanto, elija una convención y cúmplala, para que nunca tenga que mover los usos.
Las plantillas de Visual Studio, por defecto, colocan los usos fuera del espacio de nombres (por ejemplo, si hace que VS genere una nueva clase en un nuevo archivo).
Una (pequeña) ventaja de tener usos externos es que puede utilizar las directivas de uso para un atributo global, por ejemplo, en
[assembly: ComVisible(false)]
lugar de[assembly: System.Runtime.InteropServices.ComVisible(false)]
.fuente
Ponerlo dentro de los espacios de nombres hace que las declaraciones sean locales a ese espacio de nombres para el archivo (en caso de que tenga múltiples espacios de nombres en el archivo), pero si solo tiene un espacio de nombres por archivo, no hay mucha diferencia si salen o no dentro del espacio de nombres.
fuente
using
Las directivas dentro de losnamespace
bloques pueden referirse a espacios de nombres relativos basados en elnamespace
bloque adjunto .De acuerdo con Hanselman - Uso de la directiva y la carga de ensamblajes ... y otros artículos similares técnicamente no hay diferencia.
Mi preferencia es ponerlos fuera de los espacios de nombres.
fuente
My style is to put them outside the namespaces.
- apenas una respuesta en absoluto.Según la documentación de StyleCop:
SA1200: UsingDirectivesMustBePlacedWithinNamespace
Causa AC # usando directiva se coloca fuera de un elemento de espacio de nombres.
Descripción de la regla Se produce una violación de esta regla cuando una directiva using o una directiva using-alias se coloca fuera de un elemento de espacio de nombres, a menos que el archivo no contenga ningún elemento de espacio de nombres.
Por ejemplo, el siguiente código daría lugar a dos violaciones de esta regla.
Sin embargo, el siguiente código no daría lugar a ninguna violación de esta regla:
Este código se compilará limpiamente, sin errores de compilación. Sin embargo, no está claro qué versión del tipo Guid se está asignando. Si la directiva using se mueve dentro del espacio de nombres, como se muestra a continuación, se producirá un error del compilador:
El código falla en el siguiente error del compilador, que se encuentra en la línea que contiene
Guid g = new Guid("hello");
CS0576: El espacio de nombres 'Microsoft.Sample' contiene una definición en conflicto con el alias 'Guid'
El código crea un alias para el tipo System.Guid llamado Guid, y también crea su propio tipo llamado Guid con una interfaz de constructor coincidente. Más tarde, el código crea una instancia del tipo Guid. Para crear esta instancia, el compilador debe elegir entre las dos definiciones diferentes de Guid. Cuando la directiva using-alias se coloca fuera del elemento de espacio de nombres, el compilador elegirá la definición local de Guid definida dentro del espacio de nombres local, e ignorará por completo la directiva using-alias definida fuera del espacio de nombres. Esto, desafortunadamente, no es obvio al leer el código.
Sin embargo, cuando la directiva using-alias se coloca dentro del espacio de nombres, el compilador debe elegir entre dos tipos Guid diferentes y conflictivos, ambos definidos dentro del mismo espacio de nombres. Ambos tipos proporcionan un constructor coincidente. El compilador no puede tomar una decisión, por lo que marca el error del compilador.
Colocar la directiva using-alias fuera del espacio de nombres es una mala práctica porque puede generar confusión en situaciones como esta, donde no es obvio qué versión del tipo se está utilizando realmente. Potencialmente, esto puede conducir a un error que puede ser difícil de diagnosticar.
Colocar directivas con alias dentro del elemento de espacio de nombres elimina esto como fuente de errores.
Colocar múltiples elementos de espacio de nombres dentro de un solo archivo generalmente es una mala idea, pero si esto se hace, es una buena idea colocar todos los directorios que usan dentro de cada uno de los elementos de espacio de nombres, en lugar de globalmente en la parte superior del archivo. Esto abarcará estrechamente los espacios de nombres y también ayudará a evitar el tipo de comportamiento descrito anteriormente.
Es importante tener en cuenta que cuando el código se ha escrito utilizando directivas colocadas fuera del espacio de nombres, se debe tener cuidado al mover estas directivas dentro del espacio de nombres, para asegurarse de que esto no cambie la semántica del código. Como se explicó anteriormente, la colocación de directivas using-alias dentro del elemento de espacio de nombres permite al compilador elegir entre tipos en conflicto de formas que no sucederán cuando las directivas se coloquen fuera del espacio de nombres.
Cómo corregir infracciones Para corregir una infracción de esta regla, mueva todas las directivas y directivas con alias dentro del elemento de espacio de nombres.
fuente
using
s fuera del espacio de nombres. El interior meusing
parece tan feo. :)Existe un problema con la colocación de declaraciones de uso dentro del espacio de nombres cuando desea utilizar alias. El alias no se beneficia de las
using
declaraciones anteriores y tiene que estar completamente calificado.Considerar:
versus:
Esto puede ser particularmente pronunciado si tiene un alias de largo aliento como el siguiente (que es cómo encontré el problema):
Con
using
declaraciones dentro del espacio de nombres, de repente se convierte en:No es bonito.
fuente
class
necesita un nombre (identificador). No puede tener unausing
directiva dentro de una clase como lo indica. Debe estar en un nivel de espacio de nombres, por ejemplo fuera del más externonamespace
, o solo dentro del más internonamespace
(pero no dentro de una clase / interfaz / etc.).using
directivas erróneamente. Lo he editado como pretendía que fuera. Gracias por señalarlo. Sin embargo, el razonamiento sigue siendo el mismo.Como dijo Jeppe Stig Nielsen , este hilo ya tiene excelentes respuestas, pero también pensé que valía la pena mencionar esta sutileza bastante obvia.
using
Las directivas especificadas dentro de los espacios de nombres pueden hacer que el código sea más corto ya que no necesitan estar completamente calificadas como cuando se especifican en el exterior.El siguiente ejemplo funciona porque los tipos
Foo
yBar
son a la vez en el mismo espacio de nombres global,Outer
.Presume el archivo de código Foo.cs :
Y Bar.cs :
Eso puede omitir el espacio de nombres externo en la
using
directiva, para abreviar:fuente
Me encontré con una arruga (que no está cubierta en otras respuestas):
Supongamos que tiene estos espacios de nombres:
Cuando se usa
using Something.Other
fuera de anamespace Parent
, se refiere al primero (Something.Other).Sin embargo, si lo usa dentro de esa declaración de espacio de nombres, ¡se refiere a la segunda (Parent.Something.Other)!
Hay una solución simple: agregue el
global::
prefijo " ": docsfuente
Las razones técnicas se discuten en las respuestas y creo que al final se trata de las preferencias personales ya que la diferencia no es tan grande y hay compensaciones para ambos. La plantilla predeterminada de Visual Studio para crear
.cs
archivos usausing
directivas fuera de los espacios de nombres, por ejemploSe puede ajustar stylecop para verificar
using
directivas fuera de los espacios de nombres agregando unstylecop.json
archivo en la raíz del archivo del proyecto con lo siguiente:Puede crear este archivo de configuración en el nivel de solución y agregarlo a sus proyectos como 'Archivo de enlace existente' para compartir la configuración en todos sus proyectos también.
fuente
Otra sutileza que no creo que haya sido cubierta por las otras respuestas es cuando tienes una clase y un espacio de nombres con el mismo nombre.
Cuando tenga la importación dentro del espacio de nombres, encontrará la clase. Si la importación está fuera del espacio de nombres, la importación se ignorará y la clase y el espacio de nombres deberán estar completamente calificados.
fuente
Es una mejor práctica si los que usan por defecto, es decir, las " referencias " utilizadas en su solución de origen deben estar fuera de los espacios de nombres y aquellos que son "nueva referencia agregada" es una buena práctica si debe colocarla dentro del espacio de nombres. Esto es para distinguir qué referencias se están agregando.
fuente