¿Las directivas de "uso" deberían estar dentro o fuera del espacio de nombres en C#?

Resuelto benPearce asked hace 16 años • 15 respuestas

He estado ejecutando StyleCop sobre código C# y sigue informando que mis usingdirectivas deberían estar dentro del espacio de nombres.

¿Existe alguna razón técnica para colocar las usingdirectivas dentro en lugar de fuera del espacio de nombres?

benPearce avatar Sep 24 '08 10:09 benPearce
Aceptado

En realidad, existe una diferencia (sutil) entre los dos. Imagine que tiene el siguiente código en File1.cs:

// File1.cs
using System;
namespace Outer.Inner
{
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Ahora imagina que alguien agrega otro archivo (File2.cs) al proyecto que se ve así:

// File2.cs
namespace Outer
{
    class Math
    {
    }
}

El compilador busca Outerantes de mirar esas usingdirectivas fuera del espacio de nombres, por lo que encuentra Outer.Mathen lugar de System.Math. Desafortunadamente (¿o tal vez afortunadamente?), Outer.Mathno tiene ningún PImiembro, por lo que File1 ahora está roto.

Esto cambia si coloca la usingdeclaración dentro de su 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 Systemantes de buscar Outer, encuentra System.Mathy todo está bien.

Algunos dirían que Mathpodría ser un mal nombre para una clase definida por el usuario, ya que ya existe una en System; El punto aquí es que hay una diferencia y afecta la capacidad de mantenimiento de su código.

También es interesante observar qué sucede si Fooestá en el espacio de nombres Outer, en lugar de Outer.Inner. En ese caso, agregar Outer.Mathel Archivo2 rompe el Archivo1 independientemente de dónde usingvaya. Esto implica que el compilador busca el espacio de nombres más interno antes de mirar cualquier usingdirectiva.

Charlie avatar Sep 30 '2008 02:09 Charlie

Este hilo ya tiene algunas respuestas excelentes, pero creo que puedo aportar un poco más de detalles con esta respuesta adicional.

Primero, recuerde que una declaración de espacio de nombres con puntos, como:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

es totalmente equivalente a:

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

Si quisieras, podrías poner usingdirectivas en todos estos niveles. (Por supuesto, queremos tener usings 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 la siguiente manera: primero busque una coincidencia en el "alcance" más interno, si no encuentra nada allí, salga de 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, abandone (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 exteriores:

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 saber de qué tipo Ambiguouses, la búsqueda va en este orden:

  1. Tipos anidados internos C(incluidos los tipos anidados heredados)
  2. Tipos en el espacio de nombres actualMyCorp.TheProduct.SomeModule.Utilities
  3. Tipos en el espacio de nombresMyCorp.TheProduct.SomeModule
  4. tipos enMyCorp.TheProduct
  5. tipos enMyCorp
  6. Tipos en el espacio de nombres nulo (el espacio de nombres global)
  7. Escribe System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.IntegrationyThirdParty

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 Ambiguousen este orden:

  1. Tipos anidados internos C(incluidos los tipos anidados heredados)
  2. Tipos en el espacio de nombres actualMyCorp.TheProduct.SomeModule.Utilities
  3. Escribe System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.IntegrationyThirdParty
  4. Tipos en el espacio de nombresMyCorp.TheProduct.SomeModule
  5. tipos enMyCorp
  6. Tipos en el espacio de nombres nulo (el espacio de nombres global)

(Tenga en cuenta que MyCorp.TheProductera 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 agregue más adelante un nuevo tipo con nombre idéntico a uno de los espacios de nombres que tiene 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 es posible que se encuentre otro tipo. Por lo tanto, elija una convención y cúmplala, de modo que nunca tenga que cambiar de uso.

Las plantillas de Visual Studio, de forma predeterminada, colocan los usos fuera del espacio de nombres (por ejemplo, si hace que VS genere una nueva clase en un archivo nuevo).

Una (pequeña) ventaja de tener usos externos es que luego puedes utilizar las directivas de uso para un atributo global, por ejemplo, [assembly: ComVisible(false)]en lugar de [assembly: System.Runtime.InteropServices.ComVisible(false)].


Actualización sobre declaraciones de espacios de nombres con ámbito de archivo

Desde C# 10.0 (a partir de 2021), puedes evitar la sangría y usar cualquiera de las dos (convención 1, usos externos):

using System;
using System.Collections.Generic;
using System.Linq;
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities;

class C
{
    Ambiguous a;
}

o (convención 2, usos internos):

namespace MyCorp.TheProduct.SomeModule.Utilities;

using System;
using System.Collections.Generic;
using System.Linq;
using MyCorp.TheProduct;
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

class C
{
    Ambiguous a;
}

Pero se aplican las mismas consideraciones que antes.

Jeppe Stig Nielsen avatar Apr 18 '2013 21:04 Jeppe Stig Nielsen

Ponerlo dentro de los espacios de nombres hace que las declaraciones sean locales para ese espacio de nombres del 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 salen 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;
}
Mark Cidade avatar Sep 24 '2008 03:09 Mark Cidade

Según Hanselman - Directiva de uso y carga de ensamblaje... y otros artículos similares, técnicamente no hay diferencia.

Mi preferencia es ponerlos fuera de los espacios de nombres.

Quintin Robinson avatar Sep 24 '2008 03:09 Quintin Robinson