Menu

Directiva using y namespaces en C#: alias, using static y global using

Cómo organizan los namespaces de C# los tipos y cómo los importa la directiva using: alias, using static, nombres completos, resolver referencias ambiguas, usings globales y namespaces con ámbito de archivo.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Todo tipo de .NET tiene un nombre completo formado por un namespace y el nombre del tipo: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. Los namespaces agrupan tipos relacionados y evitan que los nombres choquen, así que tu propia clase Order o Timer puede convivir con las de las bibliotecas. La directiva using del principio de un archivo importa un namespace para que puedas usar los nombres cortos.

Salida:

Cart: tea, honey
1

Una directiva using solo afecta a los nombres en tiempo de compilación. No carga ninguna biblioteca ni añade código al programa; qué bibliotecas están disponibles lo deciden las referencias y los paquetes NuGet del proyecto. Si el compilador dice que un tipo o namespace "could not be found (are you missing a using directive or an assembly reference?)", el error CS0246, o falta la línea using o el paquete no está referenciado.

Declarar tus propios namespaces

Pon los tipos dentro de un bloque namespace. Los namespaces pueden anidarse, se escriben con puntos, y un mismo namespace puede repartirse entre muchos archivos.

Salida:

120.00 via DHL
Shop.Billing.Invoice

namespace Shop.Billing { } es una forma abreviada de namespace Shop { namespace Billing { } }. El código dentro de Shop puede referirse a Billing.Invoice sin el prefijo Shop., porque los nombres se buscan primero en los namespaces que lo contienen.

Convenciones: empieza por la empresa o el producto (Contoso.Payments), después la funcionalidad o la capa, y sigue la estructura de carpetas (Contoso.Payments/Refunds/RefundService.cs contiene Contoso.Payments.Refunds). Nunca llames a una clase igual que su namespace (Shop.Shop), porque obliga a cualificar los nombres de forma incómoda en todas partes.

Alias

using Name = Namespace.Type; da a un tipo (o a un namespace) un nombre local. Hay dos situaciones que lo piden: acortar un tipo genérico largo y resolver un choque de nombres.

Salida:

latte: 3.60
order 17

Los alias solo se aplican al archivo en el que se declaran (salvo que sean global, más abajo). En C# 12 y posteriores, un alias puede nombrar cualquier tipo, incluidas tuplas y arrays: using Point = (int X, int Y);.

Referencias ambiguas (CS0104)

Cuando dos namespaces importados contienen un tipo con el mismo nombre, usar el nombre corto es un error. El caso clásico es Timer, que existe en System.Threading, en System.Timers y (en aplicaciones de escritorio) en System.Windows.Forms:

using System.Threading;
using System.Timers;

var t = new Timer(1000);
// error CS0104: 'Timer' is an ambiguous reference between
// 'System.Timers.Timer' and 'System.Threading.Timer'

Tres soluciones, de la más local a la menos local: escribir el nombre completo (new System.Timers.Timer(1000)), añadir un alias que diga a cuál te refieres o quitar la directiva que no necesitas.

Salida:

250
System.Timers.Timer
System.Threading.Timer

Si tu propio namespace define un tipo llamado System o Console, el prefijo global:: obliga a buscar desde la raíz: global::System.Console.WriteLine("hi");. El código generado lo usa en todas partes por ese motivo.

using static

using static importa los miembros static de un solo tipo, para que puedan llamarse sin el nombre del tipo. Encaja con código que llama una y otra vez a la misma clase, como Math:

Salida:

Area: 28.27
Hypotenuse: 5
42

using static también funciona con enums (using static System.DayOfWeek; te permite escribir Monday) y con tus propias clases static. Úsalo donde los nombres cortos no sean ambiguos; un WriteLine suelto en un archivo grande puede dejar al lector preguntándose de qué writer se trata.

global using y namespaces con ámbito de archivo (C# 10)

Dos características de C# 10 recortan el código repetitivo del principio de los archivos. Un global using se aplica a todos los archivos del proyecto, y normalmente se guarda en un solo archivo como GlobalUsings.cs:

// GlobalUsings.cs, C# 10 and later
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Money = System.Decimal;

Los proyectos del SDK de .NET 6 y posteriores pueden generarlos por ti. Con <ImplicitUsings>enable</ImplicitUsings> en el .csproj (el valor por defecto en las plantillas nuevas), un proyecto de consola recibe System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading y System.Threading.Tasks; los proyectos web reciben además los namespaces de ASP.NET Core. Por eso los archivos Program.cs modernos empiezan directamente con código.

Un namespace con ámbito de archivo declara el namespace para todo el archivo con un punto y coma en lugar de un bloque, ahorrando un nivel de indentación:

// C# 10 and later
namespace Shop.Billing;

public class Invoice
{
    public decimal Amount { get; set; }
}

Un archivo solo puede tener un namespace con ámbito de archivo, y no puede mezclarse con namespaces de bloque en el mismo archivo. Los proyectos antiguos, los scripts de Unity y el código que apunta a .NET Framework usan la forma de bloque mostrada antes.

Dónde van las directivas using, y la sentencia using

Las directivas using deben ir antes de cualquier declaración de namespace o de tipo del archivo (los usings globales, antes de todo lo demás). También pueden ponerse dentro de un bloque namespace, en cuyo caso solo se aplican ahí; las guías de estilo no coinciden, y la mayor parte del código .NET las deja al principio.

La palabra clave using tiene un segundo trabajo, sin relación con el primero, dentro de los métodos: la sentencia using using (var file = File.OpenRead(path)) { ... } llama a Dispose sobre el objeto cuando termina el bloque, cerrando archivos y conexiones. Comparte la palabra clave y nada más. Consulta la página de la sentencia using.

Preguntas frecuentes

¿Qué hace using en C#?

Al principio de un archivo, using System.Text; es una directiva que importa un namespace, para que puedas escribir StringBuilder en lugar de System.Text.StringBuilder. No añade código ni carga nada; solo acorta los nombres. Dentro de un método, using (var f = ...) es otra característica, la sentencia using, que libera un objeto al final de un bloque.

¿Qué es un namespace en C#?

Un namespace es un grupo de tipos con nombre que evita choques de nombres y organiza el código, como System.Collections.Generic o MyShop.Billing. Dos clases pueden compartir nombre si están en namespaces distintos. Por convención, los namespaces siguen la estructura de carpetas y empiezan por el nombre de la empresa o del producto.

¿Qué es using static en C#?

using static System.Math; importa los miembros static de un tipo, así que puedes llamar a Sqrt(16) y leer PI sin el prefijo Math.. Funciona con cualquier clase, incluidas las tuyas y los enums. Úsalo donde los nombres cortos sigan siendo claros, como en código con muchas matemáticas.

¿Cómo arreglo "is an ambiguous reference" en C#?

El error CS0104 significa que dos namespaces importados contienen un tipo con ese nombre, por ejemplo Timer en System.Threading y en System.Timers. Escribe el nombre completo (System.Timers.Timer), quita una de las directivas using o añade un alias: using Timer = System.Timers.Timer;.

¿Qué es global using en C#?

global using System.Text; (C# 10) importa un namespace en todos los archivos del proyecto, no solo en el que aparece. Los proyectos del SDK de .NET 6 y posteriores generan automáticamente un conjunto de usings globales cuando está puesto <ImplicitUsings>enable</ImplicitUsings>, y por eso los archivos Program.cs nuevos no tienen líneas using.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR