Todo tipo no .NET tem um nome completo formado por um namespace e o nome do tipo: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. Os namespaces agrupam tipos relacionados e evitam conflitos de nomes, então a sua própria classe Order ou Timer pode coexistir com as das bibliotecas. A diretiva using no topo de um arquivo importa um namespace para que você possa usar os nomes curtos.
Saída:
Cart: tea, honey
1
Uma diretiva using só afeta nomes em tempo de compilação. Ela não carrega uma biblioteca nem adiciona código ao programa; quais bibliotecas estão disponíveis é decidido pelas referências do projeto e pelos pacotes NuGet. Se o compilador informa que um tipo ou namespace "could not be found (are you missing a using directive or an assembly reference?)", erro CS0246, ou falta a linha using ou o pacote não está referenciado.
Declarando seus próprios namespaces
Coloque os tipos dentro de um bloco namespace. Namespaces podem ser aninhados, escritos com pontos, e o mesmo namespace pode estar espalhado por muitos arquivos.
Saída:
120.00 via DHL
Shop.Billing.Invoice
namespace Shop.Billing { } é uma abreviação de namespace Shop { namespace Billing { } }. Código dentro de Shop pode se referir a Billing.Invoice sem o prefixo Shop., porque os nomes são procurados primeiro nos namespaces que os contêm.
Convenções: comece com a empresa ou o produto (Contoso.Payments), depois o recurso ou a camada, e siga a estrutura de pastas (Contoso.Payments/Refunds/RefundService.cs contém Contoso.Payments.Refunds). Nunca dê a uma classe o mesmo nome do seu namespace (Shop.Shop), o que obriga a qualificações estranhas em todo lugar.
Aliases
using Name = Namespace.Type; dá a um tipo (ou a um namespace) um nome local. Duas situações pedem isso: encurtar um tipo genérico longo e resolver um conflito.
Saída:
latte: 3.60
order 17
Aliases só valem no arquivo em que são declarados (a menos que sejam global, abaixo). No C# 12 em diante, um alias pode nomear qualquer tipo, inclusive tuplas e arrays: using Point = (int X, int Y);.
Referências ambíguas (CS0104)
Quando dois namespaces importados contêm um tipo com o mesmo nome, usar o nome curto é um erro. O caso clássico é Timer, que existe em System.Threading, em System.Timers e (em apps desktop) em 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'
Três soluções, da mais local para a menos local: escrever o nome totalmente qualificado (new System.Timers.Timer(1000)), adicionar um alias que diz qual você quer, ou remover a diretiva de que você não precisa.
Saída:
250
System.Timers.Timer
System.Threading.Timer
Se o seu próprio namespace define um tipo chamado System ou Console, o prefixo global:: força a busca a partir da raiz: global::System.Console.WriteLine("hi");. Código gerado o usa em todo lugar por esse motivo.
using static
using static importa os membros static de um único tipo, para que eles possam ser chamados sem o nome do tipo. Ele combina com código que chama a mesma classe várias e várias vezes, como Math:
Saída:
Area: 28.27
Hypotenuse: 5
42
using static também funciona com enums (using static System.DayOfWeek; permite escrever Monday) e com suas próprias classes static. Use-o onde os nomes curtos continuam sem ambiguidade; WriteLine sozinho em um arquivo grande pode deixar o leitor se perguntando de qual writer se trata.
global using e namespaces com escopo de arquivo (C# 10)
Dois recursos do C# 10 cortam a repetição no topo dos arquivos. Um global using vale para todos os arquivos do projeto e normalmente fica em um único arquivo, 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;
Projetos SDK do .NET 6 em diante podem gerar isso para você. Com <ImplicitUsings>enable</ImplicitUsings> no .csproj (o padrão nos templates novos), um projeto de console recebe System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading e System.Threading.Tasks; projetos web recebem também namespaces do ASP.NET Core. É por isso que os arquivos Program.cs modernos começam direto com código.
Um namespace com escopo de arquivo declara o namespace para o arquivo inteiro com um ponto e vírgula em vez de um bloco, economizando um nível de indentação:
// C# 10 and later
namespace Shop.Billing;
public class Invoice
{
public decimal Amount { get; set; }
}
Um arquivo só pode ter um namespace com escopo de arquivo, e ele não pode ser misturado com namespaces em bloco no mesmo arquivo. Projetos mais antigos, scripts Unity e código para .NET Framework usam a forma em bloco mostrada antes.
Onde ficam as diretivas using, e a instrução using
As diretivas using precisam vir antes de qualquer declaração de namespace ou de tipo no arquivo (os global usings antes de tudo). Elas também podem ser colocadas dentro de um bloco de namespace, e nesse caso só valem ali; os guias de estilo divergem, e a maior parte do código .NET as mantém no topo.
A palavra-chave using tem um segundo trabalho, sem relação, dentro dos métodos: a instrução using using (var file = File.OpenRead(path)) { ... } chama Dispose no objeto quando o bloco termina, fechando arquivos e conexões. Elas compartilham a palavra-chave e nada mais. Veja a página da instrução using.
Perguntas frequentes
O que o using faz em C#?
No topo de um arquivo, using System.Text; é uma diretiva que importa um namespace, para que você possa escrever StringBuilder em vez de System.Text.StringBuilder. Ela não adiciona código nem carrega nada; só encurta nomes. Dentro de um método, using (var f = ...) é outro recurso, a instrução using, que descarta um objeto no fim de um bloco.
O que é um namespace em C#?
Um namespace é um grupo de tipos com nome que evita conflitos de nomes e organiza o código, como System.Collections.Generic ou MyShop.Billing. Duas classes podem ter o mesmo nome se estiverem em namespaces diferentes. Por convenção, os namespaces seguem a estrutura de pastas e começam com o nome da empresa ou do produto.
O que é using static em C#?
using static System.Math; importa os membros static de um tipo, para que você possa chamar Sqrt(16) e ler PI sem o prefixo Math.. Funciona com qualquer classe, inclusive as suas, e com enums. Use-o onde os nomes curtos continuam claros, como em código com muita matemática.
Como resolver "is an ambiguous reference" em C#?
O erro CS0104 significa que dois namespaces importados contêm um tipo com esse nome, por exemplo Timer em System.Threading e em System.Timers. Escreva o nome totalmente qualificado (System.Timers.Timer), remova uma das diretivas using ou adicione um alias: using Timer = System.Timers.Timer;.
O que é global using em C#?
global using System.Text; (C# 10) importa um namespace para todos os arquivos do projeto, não só para aquele em que aparece. Projetos SDK do .NET 6 em diante geram um conjunto de global usings automaticamente quando <ImplicitUsings>enable</ImplicitUsings> está definido, e é por isso que os arquivos Program.cs novos não têm linhas using.