¿Deberían las directivas 'using' estar dentro o fuera del espacio de nombres?
Frecuentes
Visto 222,602 veces
2163
Yo he estado corriendo poliestilo sobre algún código C #, y sigue informando que mi using
las directivas deben estar dentro del espacio de nombres.
¿Existe una razón técnica para poner el using
directivas dentro en lugar de fuera del espacio de nombres?
12 Respuestas
2202
En realidad, existe una diferencia (sutil) entre los dos. Imagina que tienes el siguiente código en File1.cs:
// File1.cs
using System;
namespace Outer.Inner
{
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Ahora imagine que alguien agrega otro archivo (File2.cs) al proyecto que se ve así:
// File2.cs
namespace Outer
{
class Math
{
}
}
El compilador busca Outer
antes de mirar esos using
directivas fuera del espacio de nombres, por lo que encuentra Outer.Math
en lugar de System.Math
. Desafortunadamente (¿o quizás afortunadamente?), Outer.Math
no tiene PI
miembro, por lo que File1 ahora está roto.
Esto cambia si pones el using
dentro de su declaración de espacio de nombres, de la siguiente manera:
// File1b.cs
namespace Outer.Inner
{
using System;
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Ahora el compilador busca System
antes de buscar Outer
, Encuentra System.Math
y todo está bien.
Algunos dirían que Math
podría ser un mal nombre para una clase definida por el usuario, ya que ya hay una en System
; el punto aquí es solo que allí is una diferencia, y afecta la capacidad de mantenimiento de su código.
También es interesante notar lo que sucede si Foo
está en el espacio de nombres Outer
, más bien que Outer.Inner
. En ese caso, agregando Outer.Math
en File2 rompe File1 independientemente de dónde using
va. Esto implica que el compilador busca en el espacio de nombres adjunto más interno antes de mirar cualquier using
Directiva.
Respondido 13 Abr '18, 12:04
482
Este hilo ya tiene algunas respuestas excelentes, 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:
namespace MyCorp.TheProduct.SomeModule.Utilities
{
...
}
es completamente equivalente a:
namespace MyCorp
{
namespace TheProduct
{
namespace SomeModule
{
namespace Utilities
{
...
}
}
}
}
Si quisieras, podrías poner using
directivas en todos estos niveles. (Por supuesto, queremos tener using
s en un solo lugar, pero sería legal según el idioma).
La regla para resolver qué tipo está implícito, puede expresarse libremente de la siguiente manera: Primero busque el "alcance" más interno para una coincidencia, si no encuentra nada, vaya 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 ensamblado actual, elija ese y emita una advertencia del compilador. De lo contrario, ríndase (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:
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;
}
}
En el caso anterior, para averiguar qué tipo Ambiguous
es decir, la búsqueda va en este orden:
- Tipos anidados en el interior
C
(incluidos los tipos anidados heredados) - Tipos en el espacio de nombres actual
MyCorp.TheProduct.SomeModule.Utilities
- Tipos en el espacio de nombres
MyCorp.TheProduct.SomeModule
- Tipos en
MyCorp.TheProduct
- Tipos en
MyCorp
- Tipos en el nulo espacio de nombres (el espacio de nombres global)
- Tipos en
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
yThirdParty
La otra convención:
(2) Con usos en el interior:
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;
}
}
Ahora, busque el tipo Ambiguous
va en este orden:
- Tipos anidados en el interior
C
(incluidos los tipos anidados heredados) - Tipos en el espacio de nombres actual
MyCorp.TheProduct.SomeModule.Utilities
- Tipos en
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
yThirdParty
- Tipos en el espacio de nombres
MyCorp.TheProduct.SomeModule
- Tipos en
MyCorp
- Tipos en el nulo espacio de nombres (el espacio de nombres global)
(Tenga en cuenta que MyCorp.TheProduct
era parte de "3". y por lo tanto no fue 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 más tarde 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 apéguese a ella, de modo que nunca tenga que cambiar de uso.
Las plantillas de Visual Studio, por defecto, ponen los usos afuera 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 afuera es que luego puede utilizar las directivas using para un atributo global, por ejemplo [assembly: ComVisible(false)]
en lugar de [assembly: System.Runtime.InteropServices.ComVisible(false)]
.
respondido 08 nov., 13:09
196
Ponerlo dentro de los espacios de nombres hace que las declaraciones sean locales para ese espacio de nombres para el archivo (en caso de que tenga varios espacios de nombres en el archivo), pero si solo tiene un espacio de nombres por archivo, entonces no hay mucha diferencia si van al exterior o dentro del espacio de nombres.
using ThisNamespace.IsImported.InAllNamespaces.Here;
namespace Namespace1
{
using ThisNamespace.IsImported.InNamespace1.AndNamespace2;
namespace Namespace2
{
using ThisNamespace.IsImported.InJustNamespace2;
}
}
namespace Namespace3
{
using ThisNamespace.IsImported.InJustNamespace3;
}
Respondido 17 Abr '16, 15:04
los espacios de nombres proporcionan una separación lógica, no física (archivo). - Jowen
No es del todo cierto que no haya diferencia; using
directivas dentro namespace
Los bloques pueden referirse a espacios de nombres relativos basados en el namespace
cuadra. - OR Mapper
si lo se. lo establecimos en la respuesta aceptada de esta pregunta hace cinco años. - marca ciudad
59
Según Hanselman: uso de directivas y ensamblajes Cargando ... y otros artículos similares, técnicamente no hay diferencia.
Mi preferencia es colocarlos fuera de los espacios de nombres.
Respondido 22 Oct 12, 15:10
@Chris M: uh ... el enlace publicado en la respuesta indica que hay no beneficiarse de adentro versus afuera, mostrando un ejemplo que falsifica la afirmación hecha en el enlace que publicó ... - johnny
Sí, no leí completamente el hilo, pero lo compré cuando los MVP dijeron que era correcto. Un tipo lo refuta, lo explica y muestra su código más abajo ... "El IL que genera el compilador de C # es el mismo en cualquier caso. De hecho, el compilador de C # no genera precisamente nada que corresponda a cada directiva using. Las directivas using son puramente una C # ismo, y no tienen ningún significado para .NET en sí. (No es cierto para el uso de declaraciones, pero son algo bastante diferente) ". groups.google.com/group/wpf-disciples/msg/781738deb0a15c46 - Chris McKee
Incluya un resumen del enlace. Cuándo el enlace está roto (porque seguirá suceda, dado el tiempo suficiente), de repente una respuesta con 32 votos a favor solo vale la pena My style is to put them outside the namespaces.
- apenas una respuesta. - ANeves piensa que SE es malvado
La afirmación aquí es simplemente incorrecta ... hay una diferencia técnica y su propia cita lo dice ... de hecho, de eso se trata. Elimine esta respuesta errónea ... hay respuestas mucho mejores y precisas. - jim balter
53
Según la documentación de StyleCop:
SA1200: El uso de directivas debe colocarse dentro del espacio de nombres
Causa AC # using directive se coloca fuera de un elemento de espacio de nombres.
Descripción de la regla Se produce una infracció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 resultaría en dos violaciones de esta regla.
using System;
using Guid = System.Guid;
namespace Microsoft.Sample
{
public class Program
{
}
}
Sin embargo, el siguiente código no daría lugar a ninguna infracción de esta regla:
namespace Microsoft.Sample
{
using System;
using Guid = System.Guid;
public class Program
{
}
}
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:
namespace Microsoft.Sample
{
using Guid = System.Guid;
public class Guid
{
public Guid(string s)
{
}
}
public class Program
{
public static void Main(string[] args)
{
Guid g = new Guid("hello");
}
}
}
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 que entra 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. Posteriormente, 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 del 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 tiene que elegir entre dos tipos de Guid diferentes y en conflicto, 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á usando realmente. Potencialmente, esto puede conducir a un error que podría ser difícil de diagnosticar.
Colocar directivas using-alias dentro del elemento del espacio de nombres elimina esto como una fuente de errores.
- Varios espacios de nombres
Colocar varios elementos de espacio de nombres dentro de un solo archivo es generalmente una mala idea, pero si se hace esto, es una buena idea colocar todas las directivas using dentro de cada uno de los elementos del espacio de nombres, en lugar de globalmente en la parte superior del archivo. Esto limitará el alcance de los espacios de nombres y también ayudará a evitar el tipo de comportamiento descrito anteriormente.
Es importante tener en cuenta que cuando se ha escrito código con directivas using ubicadas 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, colocar directivas using-alias dentro del elemento del 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 using y las directivas using-alias dentro del elemento del espacio de nombres.
Respondido el 14 de Septiembre de 09 a las 16:09
@Jared: como señalé en mi respuesta, mi solución / solución preferida es tener solo una clase por archivo. Creo que esta es una convención bastante común. - benpearce
De hecho, ¡también es una regla de StyleCop! SA1402: El documento AC # solo puede contener una sola clase en el nivel raíz, a menos que todas las clases sean parciales y del mismo tipo. Mostrar una regla rompiendo otra solo gotea con la salsa incorrecta. - Tarea
Votado a favor por ser la primera respuesta en cubrirlo desde la perspectiva de StyleCop. Personalmente me gusta la sensación visual de using
s fuera del espacio de nombres. Interno using
s me parece tan feo. :) - nawfal
Finalmente una buena respuesta a la pregunta. Y el comentario de benPearce es irrelevante ... esto no tiene nada que ver con la cantidad de clases en el archivo. - jim balter
35
Existe un problema al colocar instrucciones using dentro del espacio de nombres cuando desea usar alias. El alias no se beneficia del anterior using
declaraciones y tiene que estar totalmente calificado.
Considerar:
namespace MyNamespace
{
using System;
using MyAlias = System.DateTime;
class MyClass
{
}
}
versus:
using System;
namespace MyNamespace
{
using MyAlias = DateTime;
class MyClass
{
}
}
Esto puede ser particularmente pronunciado si tiene un alias prolijo como el siguiente (que es como encontré el problema):
using MyAlias = Tuple<Expression<Func<DateTime, object>>, Expression<Func<TimeSpan, object>>>;
Con using
declaraciones dentro del espacio de nombres, de repente se convierte en:
using MyAlias = System.Tuple<System.Linq.Expressions.Expression<System.Func<System.DateTime, object>>, System.Linq.Expressions.Expression<System.Func<System.TimeSpan, object>>>;
No es bonito.
respondido 24 mar '16, 01:03
Su class
necesita un nombre (identificador). No puedes tener un using
directiva dentro de una clase como usted indica. Debe estar en un nivel de espacio de nombres, por ejemplo, fuera del extremo namespace
, o solo dentro de lo más interno namespace
(pero no dentro de una clase / interfaz / etc.). - Jeppe Stig Nielsen
@JeppeStigNielsen Gracias. Perdí el using
directivas por error. Lo he editado como quería que fuera. Gracias por señalarlo. Sin embargo, el razonamiento sigue siendo el mismo. - neo
8
Una arruga con la que me encontré (que no está cubierta en otras respuestas):
Suponga que tiene estos espacios de nombres:
- Algún otro
- Padre, Algo, Otro
Cuando se utiliza using Something.Other
afuera menos namespace Parent
, se refiere al primero (Algo, Otro).
Sin embargo, si lo usas 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: documentos
namespace Parent
{
using global::Something.Other;
// etc
}
Respondido el 05 de junio de 19 a las 10:06
¡Buen punto! Me encontré con el problema relacionado al trabajar con RazorGenerator. Desafortunadamente, parece que no entiende 'global ::' y lo convierte en 'using global;' :( Es una lástima que no pueda seleccionar si el 'uso' debe generarse dentro o fuera del 'espacio de nombres' ... - Alexander
4
Como Jeppe Stig Nielsen dicho, este hilo ya tiene excelentes respuestas, pero pensé que también valía la pena mencionar esta sutileza bastante obvia.
using
las directivas especificadas dentro de los espacios de nombres pueden generar un código 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
y Bar
están en el mismo espacio de nombres global, Outer
.
Presume el archivo de código Foo.cs:
namespace Outer.Inner
{
class Foo { }
}
Y Bar.cs:
namespace Outer
{
using Outer.Inner;
class Bar
{
public Foo foo;
}
}
Eso puede omitir el espacio de nombres externo en el using
directiva, para abreviar:
namespace Outer
{
using Inner;
class Bar
{
public Foo foo;
}
}
contestado el 23 de mayo de 17 a las 13:05
Es cierto que "puede omitir el espacio de nombres externo", pero eso no significa que deba hacerlo. Para mí, este es otro argumento de por qué el uso de directivas (que no sean alias como en la respuesta de @ Neo) debería salir del espacio de nombres, para forzar nombres de espacios de nombres completamente calificados. - keith robertson
4
Al citar las pautas internas de Microsoft, tenga en cuenta que están escritas por alguien que probablemente tenga menos de diez años de experiencia en codificación. En otras palabras, es probable que no se basen en nada más sólido que las preferencias personales. Especialmente en algo como C # que es tan nuevo.
Como regla, externo using
las directivas (por ejemplo, los espacios de nombres del sistema y de Microsoft) deben colocarse afuera al namespace
directiva. Son valores predeterminados que deben aplicarse en todos los casos. a menos que se especifique lo contrario. Esto debe incluir cualquiera de las bibliotecas internas de su propia organización que no formen parte del proyecto actual, o using
directivas que hacen referencia a otros espacios de nombres primarios en el mismo proyecto. Alguna using
las directivas que hacen referencia a otros módulos en el proyecto actual y el espacio de nombres deben colocarse dentro al namespace
directiva. Esto tiene dos funciones específicas:
- Proporciona una distinción visual entre módulos locales y "otros" módulos, es decir, todo lo demás.
- Encuadra las directivas locales que se aplicarán. preferencialmente sobre las directivas globales.
La última razón es significativa. Significa que es más difícil introducir un problema de referencia ambiguo que puede introducirse mediante un cambio no más significativo que Código de refactorización. Es decir, mueves un método de un archivo a otro y de repente aparece un error que no existía antes. Coloquialmente, un 'heisenbug', históricamente diabólicamente difícil de rastrear.
Como regla aún más general, una buena a seguir es esta. Si ve algo intrínseco a un idioma que parece ser una opción inútil, asuma que NO lo es. De hecho, cuanto más difícil es ver por qué existe la opción, más importante debe asumir que es. Haga la investigación sobre el soluciones diferencias entre las dos opciones y luego pensar detenidamente sobre las implicaciones. Por lo general, encontrará una solución increíblemente perspicaz e inteligente para un problema oscuro que el diseñador del lenguaje puso allí. específicamente para hacerte la vida más fácil. Esté debidamente agradecido y aprovéchelo.
Respondido 31 Jul 20, 14:07
Por otro lado, podría ser que el diseñador de funciones fuera un estudiante universitario que trabajaba en un proyecto interno y que propuso la nueva función a sus manejadores apenas más experimentados en primer lugar. Sin embargo, no estoy en desacuerdo con sus otros puntos. - jwdonahue
3
Otra sutileza que no creo que haya sido cubierta por las otras respuestas es para 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 deben estar completamente calificados.
//file1.cs
namespace Foo
{
class Foo
{
}
}
//file2.cs
namespace ConsoleApp3
{
using Foo;
class Program
{
static void Main(string[] args)
{
//This will allow you to use the class
Foo test = new Foo();
}
}
}
//file2.cs
using Foo; //Unused and redundant
namespace Bar
{
class Bar
{
Bar()
{
Foo.Foo test = new Foo.Foo();
Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
}
}
}
Respondido el 03 de Septiembre de 18 a las 09:09
2
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 que a lo grande y existen compensaciones para ambos. Plantilla predeterminada de Visual Studio para crear .cs
uso de archivos using
directivas fuera de los espacios de nombres, por ejemplo
Se puede ajustar stylecop para comprobar using
directivas fuera de los espacios de nombres mediante la adición stylecop.json
archivo en la raíz del archivo del proyecto con lo siguiente:
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace"
}
}
}
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.
Respondido el 03 de junio de 18 a las 13:06
-8
Es una mejor práctica si esos tu préstamo estudiantil usando ie "referencias"utilizado en su solución de origen debe estar fuera de los espacios de nombres y los que están "nueva referencia agregada" Es una buena práctica ponerlo dentro del espacio de nombres. Esto es para distinguir qué referencias se están agregando.
Respondido 14 Oct 14, 22:10
No, en realidad es una mala idea. No debe basar la ubicación entre las directivas de uso de ámbito local y global en el hecho de que se hayan agregado recientemente o no. En cambio, es una buena práctica ordenarlos alfabéticamente, excepto las referencias BCL, que deben ir en la parte superior. - Abel
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas c# .net namespaces stylecop code-organization or haz tu propia pregunta.
A veces hace una diferencia donde pones los usos: stackoverflow.com/questions/292535/linq-to-sql-designer-error - gius
Solo como referencia, hay implicaciones más allá de la cuestión de múltiples clases por archivo, por lo que si es nuevo en esta pregunta, siga leyendo. - Charlie
@ user-12506: esto no funciona muy bien en un equipo de desarrollo mediano a grande donde se requiere cierto nivel de coherencia de código. Y como se señaló anteriormente, si no comprende los diferentes diseños, es posible que encuentre casos extremos que no funcionen como esperaba. - benPearce
Terminología: Esos no son
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 vagamente lo mismo quevar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
. - Jeppe Stig NielsenSi nadie ya ha mencionado esto, en realidad Microsoft también recomienda poner
using
declaraciones dentro delnamespace
declaraciones, en sus directrices de codificación internas - user1451111