C# Namespaces e using
O .NET traz milhares de tipos prontos: Console, Math, StringBuilder, List<T>, File… E os seus programas vão criar mais um monte: Produto, Cliente, Pedido. Para não virar bagunça, cada tipo mora num namespace, uma espécie de "sobrenome". Nesta aula você vai entender por que o Console.WriteLine funciona sem você escrever nada antes, por que o StringBuilder não funciona, o que a linha using faz e como organizar os seus próprios tipos em namespaces.
- O que é um namespace e o que é o nome completo de um tipo (
System.Text.StringBuilder). - Como a diretiva
usingencurta esses nomes. - Quais
usingo .NET liga sozinho (os usings implícitos,ImplicitUsings) e como conferir a lista. - Como valer um
usingpara o projeto inteiro comglobal using. - Como colocar os seus tipos num namespace, com chaves ou com o namespace de arquivo (
namespace Lojinha;). - Como resolver dois tipos com o mesmo nome (apelidos) e chamar métodos sem o nome da classe (
using static). - Os erros
CS0246,CS0103,CS0104,CS1529,CS8915,CS8954eCS8955.
Todos os programas desta aula rodaram na máquina da Ana (usuária ana, computador notebook), com o .NET 10 SDK (C# 14). Os arquivos soltos ficam em ~/cs e rodam com dotnet run arquivo.cs (aula Rodar com dotnet run). Os exemplos com vários arquivos usam um projeto em ~/projetos/Lojinha (aula Projetos).
A ideia: o sobrenome dos tipos
Na escola da Ana há duas meninas chamadas Júlia. Quando a professora chama "Júlia!", as duas olham. Para não ter confusão, a escola usa o nome completo: "Júlia do 6º A" e "Júlia do 7º B". Na maior parte do tempo, porém, dentro da sala do 6º A, todo mundo diz só "Júlia", porque ali só existe uma.
Em C# é igual:
- Um namespace (em inglês, "espaço de nomes") é a "turma" do tipo. A classe
StringBuildermora no namespaceSystem.Text. - O nome completo do tipo junta os dois com ponto:
System.Text.StringBuilder. Esse nome nunca é ambíguo. - A diretiva
using("usando") é como dizer "estou dentro da sala do 6º A": depois deusing System.Text;, basta escreverStringBuilder.
Namespaces podem ter vários níveis, separados por ponto, como pastas dentro de pastas: System, System.Text, System.Collections.Generic. Mas atenção: eles não são pastas de verdade no disco; são só nomes que o compilador usa para achar os tipos.
| Tipo | Namespace | Nome completo |
|---|---|---|
Console | System | System.Console |
Math | System | System.Math |
StringBuilder | System.Text | System.Text.StringBuilder |
List<T> | System.Collections.Generic | System.Collections.Generic.List<T> |
File | System.IO | System.IO.File |
CultureInfo | System.Globalization | System.Globalization.CultureInfo |
1. O nome completo funciona sempre
Este programa monta um texto com o StringBuilder sem nenhum using. Cada tipo é escrito com o nome completo:
System.Text.StringBuilder texto = new System.Text.StringBuilder();
texto.Append("arroz");
System.Console.WriteLine(texto);
$ dotnet run completo.cs arroz
- System.Text.StringBuilder
- O nome completo: namespace
System.Text+ tipoStringBuilder. Repare que ele aparece duas vezes na linha: no tipo da variável e depois donew. - System.Console.WriteLine
- O mesmo para o
Console: namespaceSystem+ tipoConsole+ métodoWriteLine.
Funciona, mas é cansativo de escrever e de ler. É para isso que existe o using.
2. A diretiva using
Agora sem o nome completo. A Ana escreveu StringBuilder direto:
var texto = new StringBuilder();
texto.Append("Lista da Ana: ");
texto.Append("arroz, feijão");
Console.WriteLine(texto);
$ dotnet run sb.cs /home/ana/cs/sb.cs(1,17): error CS0246: O nome do tipo ou do namespace "StringBuilder" não pode ser encontrado (está faltando uma diretiva using ou uma referência de assembly?) Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"O nome do tipo ou do namespace StringBuilder não pode ser encontrado." Em inglês, para pesquisar: The type or namespace name 'StringBuilder' could not be found. O compilador procurou um tipo chamado só StringBuilder nos namespaces que ele conhece naquele arquivo e não achou. O próprio erro dá a dica: "está faltando uma diretiva using?". Está:
using System.Text;
var texto = new StringBuilder();
texto.Append("Lista da Ana: ");
texto.Append("arroz, feijão");
Console.WriteLine(texto);
$ dotnet run sb.cs Lista da Ana: arroz, feijão
- using
- "Usando": avisa o compilador para procurar tipos também neste namespace.
- System.Text
- O namespace. É o nome completo sem o tipo no fim.
- ;
- Termina a diretiva.
- (no topo)
- As diretivas
usingficam no começo do arquivo, antes de qualquer outra coisa. Fora do lugar, dão o erroCS1529(veja Quando dá errado).
using não "carrega" nada
Quem vem de outras linguagens às vezes acha que o using "importa" ou "inclui" uma biblioteca. Não é isso: ele só encurta nomes. O programa com using System.Text; e o programa com System.Text.StringBuilder escrito por extenso são exatamente o mesmo programa depois de compilados. Um using a mais não deixa o programa mais lento nem maior.
using System; não liga o System.Text
Como os nomes parecem pastas, é natural achar que using System; traz tudo o que começa com System. Não traz: cada using vale para um namespace, sem os "de dentro". Para usar StringBuilder, é preciso using System.Text;, mesmo que System já esteja ligado.
A palavra using tem outro uso em C#, bem diferente: o comando using (…), que fecha arquivos e conexões. Esse fica para a aula using e IDisposable. Nesta aula, using é sempre a diretiva do topo do arquivo.
Missão: rode e veja o erro CS0246. Depois acrescente, na primeira linha, a diretiva using do namespace do StringBuilder e rode de novo.
var texto = new StringBuilder();
texto.Append("Lista da Ana: ");
texto.Append("arroz, feijão");
Console.WriteLine(texto);
using System.Text;
var texto = new StringBuilder();
texto.Append("Lista da Ana: ");
texto.Append("arroz, feijão");
Console.WriteLine(texto);
3. Os usings implícitos (ImplicitUsings) .NET 6+
Se o StringBuilder precisa de using, por que o Console não precisa? O Console mora em System, e ninguém escreveu using System;…
A resposta: desde o .NET 6, o próprio dotnet acrescenta alguns using sozinho, sem aparecer no seu arquivo. São os usings implícitos (implicit usings). Dá para ver a lista: o dotnet run ola.cs monta um projeto escondido em ~/.local/share/dotnet/runfile/, e lá dentro há um arquivo gerado com eles:
$ dotnet run ola.cs Olá, mundo! $ cat ~/.local/share/dotnet/runfile/ola-*/obj/debug/ola.GlobalUsings.g.cs // <auto-generated/> global using System; global using System.Collections.Generic; global using System.IO; global using System.Linq; global using System.Net.Http; global using System.Threading; global using System.Threading.Tasks;
São sete namespaces, ligados em todo programa console do .NET 10:
| Namespace | O que traz (exemplos) | Aula |
|---|---|---|
System | Console, Math, Random, DateTime, int.Parse, as exceções básicas | Saída |
System.Collections.Generic | List<T>, Dictionary<TKey, TValue>, HashSet<T> | Coleções |
System.IO | File, Directory, Path, StreamReader | Arquivos |
System.Linq | Where, Select, Sum, OrderBy | LINQ |
System.Net.Http | HttpClient (baixar páginas da internet) | — |
System.Threading | Thread, CancellationToken | Threads |
System.Threading.Tasks | Task, Parallel | Task |
Tudo o que estiver fora dessa lista precisa de using: System.Text (StringBuilder), System.Globalization (CultureInfo), System.Text.Json, System.Text.RegularExpressions (Regex), System.Diagnostics (Stopwatch)…
De onde vem essa lista
Num projeto criado com dotnet new console, a chave fica à vista, no arquivo .csproj (aula O Arquivo .csproj):
$ cat Lojinha.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
<ImplicitUsings>enable</ImplicitUsings> quer dizer "usings implícitos: ligados". O dotnet run arquivo.cs usa a mesma configuração, só que sem mostrar o .csproj. Num projeto, a lista gerada fica em obj/Debug/net10.0/Lojinha.GlobalUsings.g.cs, com os mesmos sete.
Para ver o que acontece sem eles, a Ana desligou a chave no próprio arquivo, com uma diretiva #:property (só existe nos arquivos rodados com dotnet run arquivo.cs):
#:property ImplicitUsings=disable
Console.WriteLine("Olá");
$ dotnet run semimp.cs /home/ana/cs/semimp.cs(2,1): error CS0103: O nome "Console" não existe no contexto atual Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Sem o using System; implícito, o compilador não sabe mais quem é Console. É assim que eram todos os programas antes do .NET 6: o arquivo começava com uma fileira de using. Você ainda vai ver muito código assim em livros e na internet:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lojinha
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Olá");
}
}
}
Com os usings implícitos ligados, escrever using System; de novo não dá erro nem aviso: é só redundante. A aula Program.cs e o Main explica o resto desse modelo antigo.
4. global using: um using para o projeto inteiro C# 10
Um using normal vale só no arquivo em que foi escrito. Num projeto com dez arquivos que usam StringBuilder, seriam dez using System.Text;. A palavra global resolve isso: global using vale para todos os arquivos do projeto. Os usings implícitos, aliás, são exatamente isso: as sete linhas global using do arquivo gerado.
A lojinha da Ana virou um projeto com uma pasta Modelos. O arquivo Etiqueta.cs usa StringBuilder:
namespace Lojinha.Modelos;
public static class Etiqueta
{
public static string Montar(Produto p)
{
var sb = new StringBuilder();
sb.Append(p.Nome.ToUpper());
sb.Append(" ... ");
sb.Append(p.Preco.ToString("C"));
return sb.ToString();
}
}
(A primeira linha, namespace Lojinha.Modelos;, é explicada na próxima seção.) Sem using System.Text;, o erro já é conhecido; repare que agora ele aponta o arquivo dentro da pasta e, no fim, o projeto entre colchetes:
$ dotnet run /home/ana/projetos/Lojinha/Modelos/Etiqueta.cs(7,22): error CS0246: O nome do tipo ou do namespace "StringBuilder" não pode ser encontrado (está faltando uma diretiva using ou uma referência de assembly?) [/home/ana/projetos/Lojinha/Lojinha.csproj] Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
A Ana criou um arquivo só para os usings globais. O nome GlobalUsings.cs é costume, não obrigação:
global using System.Text;
$ dotnet run CADERNO ... R$ 12,50
Pronto: System.Text passou a valer em Program.cs, em Modelos/Etiqueta.cs e em qualquer arquivo novo.
A outra forma: no .csproj
Em vez do arquivo GlobalUsings.cs, dá para pedir o mesmo no .csproj, com um item <Using>:
$ cat Lojinha.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Text" />
</ItemGroup>
</Project>
$ dotnet run
CADERNO ... R$ 12,50
$ tail -3 obj/Debug/net10.0/Lojinha.GlobalUsings.g.cs
global using System.Text;
global using System.Threading;
global using System.Threading.Tasks;
O dotnet acrescentou global using System.Text; ao arquivo gerado, junto com os sete de sempre. As duas formas dão o mesmo resultado; escolha uma por projeto e use sempre ela, para ninguém precisar procurar em dois lugares.
global using é bom para o que quase todo arquivo usa. Para algo que só um ou dois arquivos usam (System.Text.Json, por exemplo), um using normal no próprio arquivo deixa mais claro de onde vêm os tipos.
Missão: este "projeto" tem três abas. A Etiqueta.cs usa StringBuilder e não compila. Sem mexer nela, escreva na aba GlobalUsings.cs um global using que conserte o projeto inteiro.
using Lojinha.Modelos;
var caderno = new Produto("Caderno", 12.50m);
Console.WriteLine(Etiqueta.Montar(caderno));
namespace Lojinha.Modelos;
public record Produto(string Nome, decimal Preco);
public static class Etiqueta
{
public static string Montar(Produto p)
{
var sb = new StringBuilder();
sb.Append(p.Nome.ToUpper());
sb.Append(" ... ");
sb.Append(p.Preco.ToString("C"));
return sb.ToString();
}
}
// escreva aqui o global using
global using System.Text;
5. Os seus tipos num namespace
Até aqui, os tipos que você criou (classes, records) ficaram sem namespace, no chamado namespace global. Para programas de um arquivo, tudo bem. Num projeto de verdade, cada tipo deve morar num namespace com o nome do projeto, como Lojinha ou Lojinha.Modelos. Há duas formas de escrever isso.
Com chaves: namespace Nome { … }
A forma clássica abre um bloco, e tudo o que estiver dentro das chaves pertence ao namespace:
using Lojinha;
var p = new Produto("Caderno", 12.50m);
Console.WriteLine($"{p.Nome}: {p.Preco:C}");
Console.WriteLine(typeof(Produto).FullName);
Console.WriteLine(typeof(Produto).Namespace);
namespace Lojinha
{
record Produto(string Nome, decimal Preco);
}
$ dotnet run loja.cs Caderno: R$ 12,50 Lojinha.Produto Lojinha
- using Lojinha;
- O código de cima (as instruções de nível superior) fica no namespace global. Para enxergar
Produtosó pelo nome curto, ele precisa desteusing, como para qualquer namespace do .NET. - typeof(Produto).FullName
typeofdá informações sobre um tipo (aula Reflexão).FullNameé o nome completo:Lojinha.Produto.- typeof(Produto).Namespace
- Só o namespace:
Lojinha. - namespace Lojinha
- Abre o namespace
Lojinha. - { record Produto(…); }
- Tudo dentro das chaves pertence a
Lojinha. Pode haver vários tipos ali dentro.
Num arquivo rodado com dotnet run arquivo.cs, as instruções de nível superior vêm primeiro, e os namespaces com chaves vêm depois delas, no fim do arquivo.
O namespace de arquivo: namespace Nome; C# 10
Quase sempre, um arquivo inteiro pertence a um namespace só. Para isso o C# 10 criou uma forma mais curta, o namespace de arquivo (file-scoped namespace): uma linha com ponto e vírgula, sem chaves, e tudo o que vem depois no arquivo pertence a ele. É a forma que o guia usa nos projetos, e a que você vai ver em código novo:
namespace Lojinha.Modelos; public record Produto(string Nome, decimal Preco);
using Lojinha.Modelos;
var caderno = new Produto("Caderno", 12.50m);
Console.WriteLine($"{caderno.Nome}: {caderno.Preco:C}");
$ dotnet run Caderno: R$ 12,50
- namespace Lojinha.Modelos;
- "Daqui até o fim do arquivo, tudo é do namespace
Lojinha.Modelos." Economiza um nível de recuo em todo o arquivo. - public record Produto(…)
- O nome completo do tipo passa a ser
Lojinha.Modelos.Produto. Opublicdeixa outros projetos usarem o tipo (aula public, private e internal). - using Lojinha.Modelos;
- No
Program.cs, que está em outro arquivo, ousingfazProdutovaler sem o nome completo.
| Com chaves | De arquivo | |
|---|---|---|
| Sintaxe | namespace Lojinha { … } | namespace Lojinha; |
| Vale para | o que está dentro das chaves | o arquivo todo, da linha para baixo |
| Quantos por arquivo | vários | um só (e não se mistura com o de chaves) |
| Com instruções de nível superior | sim, depois delas | não (o arquivo do Program.cs fica sem namespace) |
| Desde | C# 1 | C# 10 (.NET 6) |
Os costumes dos programadores C#
- O namespace começa com o nome do projeto e segue as pastas: o arquivo
Modelos/Produto.csdo projetoLojinhafica emLojinha.Modelos. O compilador não obriga, mas todo mundo espera isso. - Nomes em PascalCase, como os tipos:
Lojinha.Modelos, nuncalojinha.modelos. - Um tipo por arquivo, com o mesmo nome do tipo (
Produto.csguardaProduto). - Nunca dê ao namespace o mesmo nome de uma classe de dentro dele (
Lojinha.Lojinhaconfunde o compilador e as pessoas).
O editor do guia compila todas as abas juntas, como um projeto. Assim, você pode praticar com um arquivo por tipo:
Missão: o Produto está no namespace Lojinha.Modelos (aba Produto.cs), mas o Program.cs não o encontra. Rode, leia o erro e conserte o Program.cs com uma diretiva using.
var caderno = new Produto("Caderno", 12.50m);
Console.WriteLine($"Etiqueta: {caderno.Nome}");
namespace Lojinha.Modelos; public record Produto(string Nome, decimal Preco);
using Lojinha.Modelos;
var caderno = new Produto("Caderno", 12.50m);
Console.WriteLine($"Etiqueta: {caderno.Nome}");
6. Dois tipos com o mesmo nome
A lojinha cresceu. O controle de estoque tem um Produto com quantidade, e o caixa tem outro Produto com preço. Cada um no seu namespace, sem problema nenhum: os nomes completos são diferentes. O problema aparece quando um arquivo liga os dois:
using Lojinha.Estoque;
using Lojinha.Vendas;
var item = new Produto("Caneta");
Console.WriteLine(item);
namespace Lojinha.Estoque
{
record Produto(string Nome);
}
namespace Lojinha.Vendas
{
record Produto(string Nome);
}
$ dotnet run ambiguo.cs /home/ana/cs/ambiguo.cs(4,16): error CS0104: "Produto" é uma referência ambígua entre "Lojinha.Estoque.Produto" e "Lojinha.Vendas.Produto" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"Referência ambígua" (is an ambiguous reference between): são as duas Júlias. O compilador não adivinha qual você quis. Três saídas:
- Nome completo na linha que usa:
new Lojinha.Estoque.Produto("Caneta"). - Tirar um dos
using, se o arquivo só precisa de um dos dois. - Um apelido (alias), a forma mais legível quando o arquivo precisa dos dois.
Apelidos: using Apelido = Namespace;
using Estoque = Lojinha.Estoque;
using Vendas = Lojinha.Vendas;
var noDeposito = new Estoque.Produto("Caneta", 40);
var naNota = new Vendas.Produto("Caneta", 2.50m);
Console.WriteLine(noDeposito);
Console.WriteLine(naNota);
namespace Lojinha.Estoque
{
record Produto(string Nome, int Quantidade);
}
namespace Lojinha.Vendas
{
record Produto(string Nome, decimal Preco);
}
$ dotnet run apelido.cs
Produto { Nome = Caneta, Quantidade = 40 }
Produto { Nome = Caneta, Preco = 2,50 }
- using Estoque = Lojinha.Estoque;
- Cria o apelido
Estoquepara o namespaceLojinha.Estoque. Repare que ele não liga o namespace:Produtosozinho continua desconhecido. SóEstoque.Produtofunciona. - new Estoque.Produto("Caneta", 40)
- Lê-se "o
Produtodo estoque". Fica claro de qual dos dois se trata. - Console.WriteLine(noDeposito)
- Um record mostra o nome do tipo e os valores (aula Records). O nome do tipo aparece curto, sem o namespace.
O apelido também pode ser de um tipo só: using ProdutoDoCaixa = Lojinha.Vendas.Produto;. Desde o C# 12, pode ser de qualquer tipo, até de uma tupla:
using Ponto = (int X, int Y); Ponto p = (3, 4); Console.WriteLine(p);
$ dotnet run tupla.cs (3, 4)
A marca C# 12 vale para esse último caso (apelido de tupla, de array e de outros tipos sem nome). Apelidos de namespaces e de classes existem desde o C# 1.
7. using static: métodos sem o nome da classe C# 6
Há uma terceira forma de diretiva. using static recebe uma classe (não um namespace) e deixa você usar os membros estáticos dela sem escrever o nome da classe:
using static System.Math; using static System.Console; double raio = 2; WriteLine(PI * Pow(raio, 2)); WriteLine(Max(3, 8));
$ dotnet run estatico.cs 12,566370614359172 8
- using static System.Math;
PI,PoweMaxpassam a valer sem oMath.na frente (aula Matemática).- using static System.Console;
WriteLinesem oConsole..- 12,566370614359172
- A área do círculo de raio 2. A vírgula é a da cultura pt-BR da Ana (aula Cultura).
Use com moderação. Numa conta cheia de Math, ajuda. Mas quem lê WriteLine(…) num programa grande fica sem saber de onde ele veio. O guia continua escrevendo Console.WriteLine.
Formas diferentes, qual usar
| Situação | Forma |
|---|---|
| Usar um tipo uma vez, num lugar só | Nome completo: System.Text.StringBuilder |
| Usar tipos de um namespace num arquivo | using System.Text; no topo do arquivo |
| Um namespace que quase todo arquivo do projeto usa | global using System.Text; num GlobalUsings.cs, ou <Using Include="System.Text" /> no .csproj |
| Console, listas, arquivos, LINQ | Nada: já vêm nos usings implícitos |
| Os seus tipos num projeto | Namespace de arquivo: namespace Lojinha.Modelos; |
Tipos depois das instruções, num arquivo do dotnet run arquivo.cs | Namespace com chaves: namespace Lojinha { … } |
| Dois tipos com o mesmo nome no mesmo arquivo | Apelido: using Estoque = Lojinha.Estoque; |
Conta com muitos Math. | using static System.Math; |
Quando dá errado
Você já viu este erro com o StringBuilder. Ele também aparece quando o using tem um nome que não existe. A Ana escreveu Modelo em vez de Modelos:
using Lojinha.Modelo;
Console.WriteLine("oi");
$ dotnet run nsinex.cs /home/ana/cs/nsinex.cs(1,7): error CS0246: O nome do tipo ou do namespace "Lojinha" não pode ser encontrado (está faltando uma diretiva using ou uma referência de assembly?) Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: neste arquivo não existe nenhum namespace Lojinha. Com o tipo certo e o using faltando, o erro aponta o nome do tipo; com o using errado, aponta a própria linha do using (coluna 7).
Como consertar: confira a grafia do namespace (maiúsculas contam: lojinha ≠ Lojinha) e se ele existe mesmo. Para tipos do .NET, a documentação de cada tipo diz o namespace. Se for um pacote NuGet que ainda não foi instalado, falta o pacote, não o using (aula Pacotes NuGet).
O que significa: o compilador não sabe quem é Console. Num programa normal do .NET 10 isso não acontece, porque System vem nos usings implícitos. Se aconteceu, os usings implícitos estão desligados: <ImplicitUsings>disable</ImplicitUsings> no .csproj, #:property ImplicitUsings=disable no arquivo, ou um projeto antigo, de antes do .NET 6.
Como consertar: escreva using System; no topo, ou ligue de novo os usings implícitos (enable).
O que significa: dois namespaces ligados por using têm um tipo com o mesmo nome.
Como consertar: use o nome completo, tire o using que sobra ou crie um apelido (using Estoque = Lojinha.Estoque;).
using fora do lugar
Console.WriteLine("oi");
using System.Text;
$ dotnet run ordem.cs /home/ana/cs/ordem.cs(2,1): error CS1529: Uma cláusula using deve preceder todos os outros elementos definidos no namespace, exceto as declarações de alias externas Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: "uma cláusula using deve vir antes de todos os outros elementos". As diretivas ficam no topo do arquivo, antes das instruções e dos tipos.
Como consertar: suba a linha do using para o começo do arquivo.
global using depois de um using normal
using System.Text;
global using System.Globalization;
Console.WriteLine("Olá");
$ dotnet run glob.cs /home/ana/cs/glob.cs(2,1): error CS8915: Uma diretiva de uso global deve preceder todas as diretivas de uso não global. Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: dentro de um arquivo, os global using vêm primeiro, depois os using normais.
Como consertar: inverta as duas linhas ou, melhor ainda, mova os global using para um arquivo só deles (GlobalUsings.cs).
namespace Lojinha;
namespace Outro
{
class A { }
}
$ dotnet run misto.cs /home/ana/cs/misto.cs(3,11): error CS8955: O arquivo de origem não pode conter declarações de namespace normal e escopo de arquivo. Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
E com dois namespaces de arquivo (namespace Lojinha; e, logo abaixo, namespace Outro;):
$ dotnet run dois.cs /home/ana/cs/dois.cs(2,11): error CS8954: O arquivo de origem só pode conter uma declaração de namespace de escopo de arquivo. Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: o namespace de arquivo vale para o arquivo inteiro, então não pode haver outro namespace no mesmo arquivo, nem de arquivo nem com chaves.
Como consertar: um namespace de arquivo por arquivo. Se precisa de dois namespaces, use dois arquivos, ou use só namespaces com chaves.
namespace Lojinha;
Console.WriteLine("oi");
class Produto { }
$ dotnet run loja3.cs /home/ana/cs/loja3.cs(3,9): error CS0116: Um namespace não pode conter diretamente membros, como campos, métodos ou instruções /home/ana/cs/loja3.cs(3,19): error CS1026: ) esperado /home/ana/cs/loja3.cs(3,19): error CS1022: Definição de namespace ou tipo, ou final do arquivo esperado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: três erros para um problema só. Depois de namespace Lojinha;, o arquivo inteiro está "dentro" do namespace, e um namespace só pode conter tipos (classes, records, structs…), não instruções soltas como o Console.WriteLine. O compilador se perde a partir dali, e os erros CS1026 e CS1022 são consequência do primeiro. Lembre a regra da aula Lendo Erros do Compilador: conserte o primeiro erro e rode de novo.
Como consertar: o arquivo com as instruções de nível superior fica sem namespace. Num projeto, coloque os tipos em outros arquivos, cada um com o seu namespace Lojinha;. Num arquivo só, use o namespace com chaves, no fim.
using duas vezes
$ dotnet run dup.cs /home/ana/cs/dup.cs(3,7): warning CS0105: A diretiva using para "System.Text" apareceu anteriormente neste namespace Olá
O que significa: é só um aviso (o programa rodou): a linha 3 repete um using System.Text; que já estava na linha 2. Apague a repetida.
Referência
| Sintaxe | O que faz |
|---|---|
System.Text.StringBuilder | Nome completo de um tipo: namespace + tipo |
using System.Text; | Liga um namespace neste arquivo: os tipos dele valem pelo nome curto |
global using System.Text; | Liga um namespace em todos os arquivos do projeto C# 10 |
<Using Include="System.Text" /> | O mesmo que o global using, escrito no .csproj |
<ImplicitUsings>enable</ImplicitUsings> | Liga os 7 usings implícitos (System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading, System.Threading.Tasks) |
#:property ImplicitUsings=disable | Desliga os usings implícitos num arquivo do dotnet run arquivo.cs |
namespace Lojinha { … } | Os tipos dentro das chaves pertencem a Lojinha |
namespace Lojinha.Modelos; | Namespace de arquivo: o arquivo todo pertence a ele C# 10 |
using Estoque = Lojinha.Estoque; | Apelido para um namespace ou tipo |
using Ponto = (int X, int Y); | Apelido para qualquer tipo, até tupla C# 12 |
using static System.Math; | Membros estáticos da classe sem o nome dela C# 6 |
typeof(T).Namespace / .FullName | O namespace / o nome completo de um tipo |
CS0246 | Tipo ou namespace não encontrado (falta using ou o nome está errado) |
CS0103 | Nome não existe (com Console: usings implícitos desligados) |
CS0104 | Referência ambígua: dois tipos com o mesmo nome |
CS1529 | using depois de outro elemento |
CS8915 | global using depois de um using normal |
CS8954 / CS8955 | Dois namespaces de arquivo / namespace de arquivo misturado com o de chaves |
CS0105 (aviso) | using repetido |
Exercícios
1. A diretiva
Complete para poder escrever StringBuilder sem o nome completo:
2. Para o projeto inteiro
Complete para que System.Globalization valha em todos os arquivos do projeto:
3. Namespace de arquivo
Complete a primeira linha do arquivo Modelos/Cliente.cs do projeto Lojinha, seguindo o costume:
4. Num programa do .NET 10 com os usings implícitos ligados, qual destes tipos precisa de um using a mais?
5. O que a diretiva using System.Text; faz?
6. Um arquivo tem using Lojinha.Estoque; e using Lojinha.Vendas;, e os dois namespaces têm um tipo Produto. O que acontece em new Produto("Caneta")?
Missão final: o programa não compila por causa do CS0104. Troque as duas diretivas por apelidos (using Estoque = …; e using Vendas = …;) e mostre os dois produtos: o do estoque com 40 unidades e o do caixa com preço 2.50m.
using Lojinha.Estoque;
using Lojinha.Vendas;
var noDeposito = new Produto("Caneta", 40);
var naNota = new Produto("Caneta", 2.50m);
Console.WriteLine(noDeposito);
Console.WriteLine(naNota);
namespace Lojinha.Estoque
{
record Produto(string Nome, int Quantidade);
}
namespace Lojinha.Vendas
{
record Produto(string Nome, decimal Preco);
}
using Estoque = Lojinha.Estoque;
using Vendas = Lojinha.Vendas;
var noDeposito = new Estoque.Produto("Caneta", 40);
var naNota = new Vendas.Produto("Caneta", 2.50m);
Console.WriteLine(noDeposito);
Console.WriteLine(naNota);
namespace Lojinha.Estoque
{
record Produto(string Nome, int Quantidade);
}
namespace Lojinha.Vendas
{
record Produto(string Nome, decimal Preco);
}
Resumo
- Todo tipo mora num namespace. O nome completo junta os dois:
System.Text.StringBuilder. using System.Text;, no topo do arquivo, deixa usar o nome curto. Ele só encurta nomes, não carrega nada, e não liga os namespaces "de dentro".- O .NET 10 liga sozinho 7 usings implícitos (
ImplicitUsings):System,System.Collections.Generic,System.IO,System.Linq,System.Net.Http,System.ThreadingeSystem.Threading.Tasks. O resto (comoSystem.Text) precisa deusing. global usingvale para o projeto inteiro. Fica numGlobalUsings.csou no.csproj(<Using Include="…" />), e vem antes dosusingnormais (CS8915).- Os seus tipos:
namespace Lojinha.Modelos;(namespace de arquivo, um por arquivo, sem instruções soltas) ounamespace Lojinha { … }(com chaves, depois das instruções de nível superior). - Dois tipos com o mesmo nome dão
CS0104: use o nome completo ou um apelido (using Estoque = Lojinha.Estoque;). using static System.Math;dispensa o nome da classe; use com moderação.