Usings Globais em C# 10 e .NET 6 em 10 Minutos ou Menos
[[academy-video-youtube({"vid": "RWYrafpP53A", "start_time": "0", "title": "Global Usings in C# 10 and .NET 6 In 10 Minutes or Less", "creator": "Tim Corey", "length": "5m 33s"})]]
Qualquer um que já tenha rolado o topo de um arquivo C# conhece a cerimônia: uma coluna de declarações de 'using' empilhadas acima de cada declaração de classe, repetindo-se de um arquivo para outro. Um projeto típico traz os mesmos poucos namespaces repetidamente, e editar todos eles quando um precisa mudar é uma tarefa que não oferece nenhum ganho real. O C# 10 adicionou a diretiva 'global using' para remover essa repetição em todo o projeto.
Em seu vídeo "Global Usings in C# 10 and .NET 6 In 10 Minutes or Less", Tim Corey explica o que os 'global usings' fazem, onde colocá-los para que a equipe possa encontrá-los, e a variante estática que permite retirar um prefixo de classe de chamadas de membro. Ele também alerta para a armadilha de design que vale a pena ter em mente: importar globalmente um namespace expõe todo o projeto a qualquer nome que exista dentro dele. Qualquer pessoa que estava copiando as mesmas cinco linhas de 'using' para cada nova classe encontrará aqui o padrão de limpeza.
O Problema da Repetição
[0:17 - 1:50] Tim começa com um aplicativo de console .NET 6 novo e cria uma pasta Data contendo uma classe PersonModel. Referenciar essa classe no Program.cs requer a esperada linha using GlobalUsings.Data; no topo do arquivo. Adicionar uma segunda classe que também precisa de PersonModel significa adicionar a mesma linha using no topo desse arquivo também. Com meia dúzia de classes, o mesmo import é escrito meia dúzia de vezes.
Esta é exatamente a situação para a qual global using foi projetado. Qualquer namespace, tipo ou classe estática que todo o projeto depende pode ser declarado uma vez e disponibilizado para cada arquivo sem a repetição por arquivo.
Promovendo um 'Using' para Escopo Global
[1:50 - 2:24] A sintaxe é uma única palavra-chave à frente da diretiva existente:
global using GlobalUsings.Data;
global using GlobalUsings.Data;
Aquela linha única, colocada em qualquer arquivo .cs do projeto, torna GlobalUsings.Data disponível em todos os outros arquivos no mesmo projeto. As outras classes que anteriormente precisavam de sua própria linha using para PersonModel não precisam mais dela; o tipo é resolvido automaticamente. O escopo para na fronteira do projeto, então referenciar classes de um projeto irmão ainda precisa da referência normal ao projeto mais seu próprio 'using' global ou por arquivo.
O que isso não faz é esconder de onde vêm os tipos. O compilador ainda resolve PersonModel para seu namespace; o namespace é apenas pré-importado. O comportamento em tempo de execução é idêntico a escrever a mesma 'using' no topo de cada arquivo.
Centralizando 'Usings' em Um Arquivo
[2:24 - 3:32] Espalhar diretivas 'global using' por arquivos aleatórios é tecnicamente permitido, mas operacionalmente bagunçado. Se um novo membro da equipe vir PersonModel resolver sem uma importação óbvia, ele terá de grep o projeto para encontrar onde ela foi tornada global. A convenção em evolução é manter todos os 'global usings' em um único arquivo na raiz do projeto, nomeado de forma previsível como Usings.cs ou GlobalUsings.cs:
// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;
// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;
O arquivo não contém mais nada. Qualquer pessoa que se juntar ao projeto sabe exatamente um lugar para olhar para ver o que está disponível globalmente. file-scoped namespaces e outros recursos para reduzir cerimônias que chegaram nas versões recentes do C#, todos com o objetivo de tornar mais fácil ler rapidamente o boilerplate do projeto.
'Using Static' Global Para Importação de Métodos
[3:32 - 4:50] A diretiva 'global using' compõe-se com o formato 'using static' que foi adicionado anteriormente. A combinação permite que você remova o prefixo de classe de um membro estático em todo o projeto. O caso motivador que Tim mostra é Console.WriteLine:
global using static System.Console;
global using static System.Console;
Com aquela linha única no arquivo de usings centralizado, Console.WriteLine("hello") torna-se simplesmente WriteLine("hello") em todo o projeto. O mesmo padrão funciona para auxiliares de matemática (using static System.Math global permite escrever Sqrt(x) sem o prefixo) e para qualquer outra classe estática que seu código utilize intensamente.
Essa é a forma sobre a qual Tim é mais cauteloso. Remover o prefixo de classe é um ganho de legibilidade quando os métodos são óbvios, mas pode se tornar uma fonte de confusão quando duas classes estáticas expõem métodos com o mesmo nome. Um leitor olhando para uma chamada WriteLine nua tem de confiar no arquivo central em vez de ver a origem no contexto.
Quando Importações Globais Entram em Conflito
[4:50 - 5:14] O objetivo inteiro dos namespaces é manter tipos com o mesmo nome curto de colidirem. Importar globalmente um namespace remove esse buffer para todo o projeto de uma vez. Se o seu namespace GlobalUsings.Data contiver uma classe Data e você também importar globalmente System.Data, todo arquivo agora terá de desambiguar. O custo aparece não onde o conflito acontece, mas em qualquer arquivo futuro que seja pego entre os dois.
A orientação de Tim é usar 'global usings' de forma deliberada, preferir namespaces que você sabe que o projeto depende universalmente e ser especialmente cuidadoso com 'global using static'. Um conjunto inicial razoável são os namespaces que cada arquivo importa de qualquer forma; aumentar a lista além disso requer uma revisão de código.
Encerrando: Menos Cerimônia, Mesmo Comportamento
[5:14 - 5:33] 'Global usings' são uma pequena funcionalidade que se paga ao longo da vida de um projeto. Cada arquivo que não carrega mais cinco linhas de importações redundantes é um arquivo que abre para o código real mais rápido, e uma edição em um namespace compartilhado acontece em um lugar em vez de dúzias. O mesmo cuidado que entra em apelidos de tipo e a família mais ampla de 'using' se aplica aqui: use-a onde o ganho de legibilidade é claro, e mantenha o arquivo central pequeno o suficiente para que o próximo desenvolvedor possa escaneá-lo de uma só vez.
Conclusão
[5:14 - 5:33] 'Global usings' substituem linhas de 'using' por arquivo por diretivas do projeto, a variante 'global using static' remove o prefixo de classe de chamadas de membro estático, e um único arquivo Usings.cs na raiz do projeto é a convenção que mantém isso descoberto. A funcionalidade é opt-in e aditiva, então adotá-la em uma base de código existente é incremental.
Dica de Exemplo: Quando você ativa as usings implícitas via <ImplicitUsings>enable</ImplicitUsings> em seu .csproj, o SDK automaticamente adiciona um conjunto selecionado de usings globais (como System, System.Linq, e System.Collections.Generic) sem que você os escreva. Combine isso com seu próprio Usings.cs para importações específicas do projeto e o topo de cada arquivo fica visivelmente mais curto.
Assista ao vídeo completo aqui em seu Canal do YouTube e obtenha mais informações sobre a estrutura do projeto C# moderno na série de Treinamento de 10 Minutos.
