Condividi tramite


Spazi dei nomi e direttive using

Suggerimento

Novità dello sviluppo di software? Iniziare prima con le esercitazioni introduttive . Introdurranno namespace e using direttive mentre scrivi i tuoi primi programmi.

Esperienza in un'altra lingua? Gli namespace in C# funzionano in modo analogo ai pacchetti in Java o ai moduli in Python. Passare alla sintassi necessaria.

Le dichiarazioni dello spazio dei nomi e le direttive using sono funzionalità del linguaggio correlate. Una dichiarazione dello spazio dei nomi organizza i tuoi tipi in una struttura ben definita. Uno spazio dei nomi raggruppa i tipi correlati e impedisce conflitti di denominazione. Una using direttiva consente al programma di utilizzare questi tipi in base ai nomi semplici. Non è necessario specificare il percorso completo dello spazio dei nomi a ogni uso.

Hai già usato i namespace in ogni programma C# che hai scritto. Ogni tipo .NET appartiene a uno spazio dei nomi e ogni using direttiva all'inizio di un file fa riferimento a uno. Ad esempio, Console e Math appartengono allo spazio dei nomi System, quindi i loro nomi completamente qualificati sono System.Console e System.Math. Tipi di raccolta come List<T> e Dictionary<TKey, TValue> appartengono a System.Collections.Generic. Una singola using direttiva per uno di questi spazi dei nomi consente di fare riferimento a tutti i loro tipi con i loro nomi semplici. Si scrive List<T> invece di System.Collections.Generic.List<T> ovunque lo si usi.

Questo articolo fornisce altre informazioni sul funzionamento degli spazi dei nomi e using delle direttive e illustra esempi di modelli già rilevati nelle librerie .NET.

Uno spazio dei nomi contiene tipi. Ogni tipo .NET appartiene a uno spazio dei nomi. Si consideri ad esempio System.Threading.Tasks.Task: il tipo Task appartiene al namespace System.Threading.Tasks.

È consigliabile raggruppare tipi correlati o simili nello stesso spazio dei nomi ed è ciò che fa .NET con i tipi forniti. Lo System.Collections.Generic spazio dei nomi contiene tipi correlati alla raccolta e lo System.IO spazio dei nomi contiene tipi correlati alla lettura e scrittura di file, directory e dati. Lo System spazio dei nomi contiene tipi fondamentali come Math, DateTimee Console.

L'esempio seguente illustra come i namespace funzionano insieme con le direttive using in un tipico file C#.

using System.Globalization;

namespace MyApp.Services;

class Greeter
{
    public string Greet(string name)
    {
        var culture = CultureInfo.CurrentCulture;
        return $"Hello, {name}! Culture: {culture.Name}";
    }
}

Nell'esempio precedente, la direttiva using indica che è possibile usare System.Globalization.CultureInfo con il nome CultureInfo senza specificare il nome completo System.Globalization.CultureInfo. La direttiva namespace dichiara che la classe Greeter fa parte del namespace MyApp.Services. Il nome completo è MyApp.Services.Greeter.

Dichiarazioni di namespace

Una dichiarazione dello spazio dei nomi assegna i tipi a un gruppo denominato. Ogni tipo che scrivi dovrebbe appartenere a uno spazio dei nomi. Il nome dello spazio dei nomi rispecchia in genere la struttura di cartelle del progetto. Ad esempio, i tipi in una cartella Services/Payments spesso appartengono allo MyApp.Services.Payments spazio dei nomi.

Gli spazi dei nomi usano l'operatore . per esprimere la gerarchia, ad esempio System.Collections.Generic. I nomi degli spazi dei nomi devono essere nomi di identificatori C# validi.

Spazi dei nomi con ambito a livello di file

Usare la sintassi con ambito file quando tutti i tipi in un file appartengono allo stesso spazio dei nomi. Aggiungi un punto e virgola dopo la dichiarazione dello spazio dei nomi; questo si applica a tutto il file. Non sono necessarie parentesi graffe o rientri aggiuntivi:

namespace MyApp.Models;

class Customer
{
    public required string Name { get; init; }
    public string? Email { get; init; }

    public override string ToString() => $"{Name} ({Email ?? "no email"})";
}

I namespace con ambito file riducono l'annidamento e semplificano la leggibilità dei file. È possibile avere una sola dichiarazione di namespace con ambito file per ogni file.

Suggerimento

Usa namespace a livello di file nel nuovo codice. La maggior parte dei modelli .NET e degli analizzatori di codice consiglia questo stile.

Spazi dei nomi con ambito blocco

Utilizzare la sintassi con scoping a blocchi quando è necessario dichiarare più namespace nello stesso file. Questo stile aggiunge un livello aggiuntivo di rientro.

Importante

È considerata una cattiva pratica dichiarare più namespace in uno stesso file. Lo scenario più comune consiste nell'usare namespace ambito di file.

Il frammento di codice seguente è un esempio di spazio dei nomi con ambito blocco :

namespace MyApp.Models
{
    class Product
    {
        public required string Name { get; init; }
        public decimal Price { get; init; }

        public override string ToString() => $"{Name}: {Price:C}";
    }
}

Utilizzo di direttive

Senza una using direttiva, è necessario fare riferimento a ogni tipo in base al nome completo, al percorso completo dello spazio dei nomi e al nome del tipo:

static void ShowFullyQualified()
{
    // Without a using directive, use the fully qualified name:
    System.Console.WriteLine("Hello from fully qualified name!");
}

Una using direttiva all'inizio di un file importa uno spazio dei nomi in modo da poter usare i relativi tipi in base ai nomi semplici:

static void ShowShortName()
{
    // With 'using System;' (or implicit usings enabled), use the short name:
    Console.WriteLine("Hello from short name!");
}

Per altre informazioni, vedere la using direttiva .

Direttive using globali

Se scrivi le stesse using direttive in ogni file, le direttive global using consentono di dichiararle una volta per l'intero progetto. Inserirli in qualsiasi file. Molti team creano un file dedicato GlobalUsings.cs :

global using System.Text;
global using System.Text.Json;

Dopo aver dichiarato un utilizzo globale, ogni file nel progetto può fare riferimento ai tipi di tale spazio dei nomi usando nomi semplici senza una direttiva aggiuntiva using .

Uso implicito

.NET SDK genera automaticamente direttive using globali per gli spazi dei nomi più comuni in base al tipo di progetto. Abilitare l'uso implicito impostando <ImplicitUsings>enable</ImplicitUsings> nel file di progetto. Ad esempio, un progetto di app console importa automaticamente System, System.Collections.Generic, System.IO, System.Linq, System.Threading e System.Threading.Tasks. L'SDK attuale consente ImplicitUsings quando si crea un nuovo progetto utilizzando dotnet new.

Per altre informazioni, vedere Direttive using implicite.

Direttive using statiche

Una static using direttiva importa i membri statici di un tipo in modo da poterli chiamare senza il prefisso del nome del tipo:

using static System.Math;

namespace MyApp.Utilities;

class CircleCalculator
{
    public static double CalculateArea(double radius) => PI * Pow(radius, 2);

    public static double CalculateCircumference(double radius) => 2 * PI * radius;
}

Gli usi statici funzionano bene per le classi di utilità come Math e Console che si chiamano di frequente.

Alias di tipo e di namespace

Un using alias crea un nome abbreviato per un tipo o uno spazio dei nomi. Gli alias sono utili per i tipi generici lunghi, la risoluzione dei conflitti di denominazione e il miglioramento della leggibilità:

using CustomerList = System.Collections.Generic.List<MyApp.Models.Customer>;

namespace MyApp.Services;

class CustomerService
{
    public CustomerList GetTopCustomers()
    {
        CustomerList customers = [new() { Name = "Alice" }, new() { Name = "Bob" }];
        return customers;
    }
}

A partire da C# 12, è possibile usare un alias per qualsiasi tipo, incluse le tuple e i tipi di puntatore:

using Point = (double X, double Y);

namespace MyApp.Geometry;

class Shape
{
    public static double Distance(Point a, Point b)
    {
        var dx = a.X - b.X;
        var dy = a.Y - b.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
}

Per scenari più avanzati in cui due assembly definiscono lo stesso nome di tipo completamente qualificato, utilizzare extern alias per disambiguare tra loro.