Menu

Direttiva using e namespace in C#: alias, using static, global using

Come i namespace di C# organizzano i tipi e come la direttiva using li importa: alias, using static, nomi completi, come risolvere i riferimenti ambigui, global using e namespace con ambito di file.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Ogni tipo in .NET ha un nome completo formato da un namespace e dal nome del tipo: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. I namespace raggruppano tipi correlati ed evitano i conflitti di nomi, così la tua classe Order o Timer può convivere con quelle delle librerie. La direttiva using in cima a un file importa un namespace, così puoi usare i nomi brevi.

Output:

Cart: tea, honey
1

Una direttiva using agisce solo sui nomi in fase di compilazione. Non carica una libreria né aggiunge codice al programma; quali librerie sono disponibili lo decidono i riferimenti del progetto e i pacchetti NuGet. Se il compilatore segnala che un tipo o un namespace "could not be found (are you missing a using directive or an assembly reference?)", errore CS0246, manca la riga using oppure il pacchetto non è referenziato.

Dichiarare i tuoi namespace

Metti i tipi dentro un blocco namespace. I namespace si possono annidare, si scrivono con i punti e lo stesso namespace può essere distribuito su molti file.

Output:

120.00 via DHL
Shop.Billing.Invoice

namespace Shop.Billing { } è una scorciatoia per namespace Shop { namespace Billing { } }. Il codice dentro Shop può riferirsi a Billing.Invoice senza il prefisso Shop., perché i nomi vengono cercati prima nei namespace che li contengono.

Convenzioni: inizia con l'azienda o il prodotto (Contoso.Payments), poi la funzionalità o il livello, e rispecchia la struttura delle cartelle (Contoso.Payments/Refunds/RefundService.cs contiene Contoso.Payments.Refunds). Non dare mai a una classe lo stesso nome del suo namespace (Shop.Shop), perché costringe a qualificazioni scomode ovunque.

Alias

using Name = Namespace.Type; dà a un tipo (o a un namespace) un nome locale. Serve in due situazioni: accorciare un tipo generico lungo e risolvere un conflitto.

Output:

latte: 3.60
order 17

Gli alias valgono solo nel file in cui sono dichiarati (a meno che non siano global, vedi sotto). Da C# 12 un alias può indicare qualsiasi tipo, comprese tuple e array: using Point = (int X, int Y);.

Riferimenti ambigui (CS0104)

Quando due namespace importati contengono un tipo con lo stesso nome, usare il nome breve è un errore. Il caso classico è Timer, che esiste in System.Threading, System.Timers e (nelle applicazioni desktop) 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'

Tre soluzioni, dalla più locale alla meno locale: scrivi il nome completo (new System.Timers.Timer(1000)), aggiungi un alias che dica quale intendi oppure rimuovi la direttiva che non ti serve.

Output:

250
System.Timers.Timer
System.Threading.Timer

Se il tuo namespace definisce un tipo chiamato System o Console, il prefisso global:: forza la ricerca a partire dalla radice: global::System.Console.WriteLine("hi");. Il codice generato lo usa ovunque proprio per questo motivo.

using static

using static importa i membri statici di un singolo tipo, così si possono chiamare senza il nome del tipo. È adatto al codice che chiama la stessa classe più e più volte, come Math:

Output:

Area: 28.27
Hypotenuse: 5
42

using static funziona anche con gli enum (using static System.DayOfWeek; ti permette di scrivere Monday) e con le tue classi statiche. Usalo dove i nomi brevi restano non ambigui; un WriteLine da solo in un file grande può lasciare chi legge a chiedersi di quale writer si tratti.

global using e namespace con ambito di file (C# 10)

Due funzionalità di C# 10 riducono il codice ripetitivo in cima ai file. Un global using vale per tutti i file del progetto, e di solito si tiene in un unico file come 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;

I progetti SDK su .NET 6 e successivi possono generarli per te. Con <ImplicitUsings>enable</ImplicitUsings> nel .csproj (il default nei nuovi template), un progetto console riceve System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading e System.Threading.Tasks; i progetti web ricevono anche i namespace di ASP.NET Core. Ecco perché i file Program.cs moderni iniziano direttamente con il codice.

Un namespace con ambito di file dichiara il namespace per tutto il file con un punto e virgola invece di un blocco, risparmiando un livello di indentazione:

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

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

Un file può avere un solo namespace con ambito di file, e non si può mescolare con namespace a blocco nello stesso file. I progetti più vecchi, gli script Unity e il codice che punta a .NET Framework usano la forma a blocco vista prima.

Dove vanno le direttive using, e l'istruzione using

Le direttive using devono venire prima di qualsiasi dichiarazione di namespace o di tipo nel file (i global using prima di tutto il resto). Si possono anche mettere dentro un blocco namespace, e in quel caso valgono solo lì; le guide di stile non sono d'accordo, e la maggior parte del codice .NET le tiene in cima.

La parola chiave using ha un secondo compito, senza relazione con il primo, dentro i metodi: l'istruzione using using (var file = File.OpenRead(path)) { ... } chiama Dispose sull'oggetto quando il blocco finisce, chiudendo file e connessioni. Condivide la parola chiave e nient'altro. Vedi la pagina sull'istruzione using.

Domande frequenti

Cosa fa using in C#?

In cima a un file, using System.Text; è una direttiva che importa un namespace, così puoi scrivere StringBuilder invece di System.Text.StringBuilder. Non aggiunge codice e non carica nulla; serve solo ad accorciare i nomi. Dentro un metodo, using (var f = ...) è una funzionalità diversa, l'istruzione using, che esegue il dispose di un oggetto alla fine di un blocco.

Cos'è un namespace in C#?

Un namespace è un gruppo di tipi con un nome che evita i conflitti di nomi e organizza il codice, come System.Collections.Generic o MyShop.Billing. Due classi possono avere lo stesso nome se stanno in namespace diversi. Per convenzione i namespace seguono la struttura delle cartelle e iniziano con il nome dell'azienda o del prodotto.

Cos'è using static in C#?

using static System.Math; importa i membri statici di un tipo, così puoi chiamare Sqrt(16) e leggere PI senza il prefisso Math.. Funziona con qualsiasi classe, comprese le tue e gli enum. Usalo dove i nomi brevi restano chiari, come nel codice pieno di calcoli matematici.

Come risolvo "is an ambiguous reference" in C#?

L'errore CS0104 significa che due namespace importati contengono entrambi un tipo con quel nome, per esempio Timer in System.Threading e in System.Timers. Scrivi il nome completo (System.Timers.Timer), rimuovi una delle direttive using oppure aggiungi un alias: using Timer = System.Timers.Timer;.

Cos'è global using in C#?

global using System.Text; (C# 10) importa un namespace in tutti i file del progetto, non solo in quello in cui compare. I progetti SDK di .NET 6 e successivi generano automaticamente un insieme di global using quando è impostato <ImplicitUsings>enable</ImplicitUsings>, ed è per questo che i nuovi file Program.cs non hanno righe using.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA