Novità di C# 11

Di seguito sono elencate le funzionalità aggiunte in C#11:

C# 11 è supportato in .NET 7. Per altre informazioni, vedere controllo delle versioni del linguaggio C#.

È possibile scaricare la versione più recente di .NET 7 SDK dalla pagina dei download di .NET. È anche possibile scaricare Visual Studio 2022, che include .NET 7 SDK.

Nota

Il feedback degli utenti su queste funzionalità è sempre molto apprezzato. Se si riscontrano problemi con una di queste nuove funzionalità, creare un nuovo problema nel repository dotnet/roslyn.

Attributi generici

È possibile dichiarare una classe generica la cui classe di base è System.Attribute. Questa funzionalità offre una sintassi più pratica per gli attributi che richiedono un parametro System.Type. Nelle versioni precedenti è necessario creare un attributo che accetta un Type come parametro del relativo costruttore:

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;

   public Type ParamType { get; }
}

E per applicare l'attributo si usa l'operatore typeof:

[TypeAttribute(typeof(string))]
public string Method() => default;

Con questa nuova funzionalità, è invece possibile creare un attributo generico:

// C# 11 feature:
public class GenericAttribute<T> : Attribute { }

Specificare quindi il parametro di tipo generico per usare l'attributo:

[GenericAttribute<string>()]
public string Method() => default;

Quando si applica l'attributo, è necessario specificare tutti i parametri di tipo generico. In altre parole, il tipo generico deve essere costruito completamente. Nell'esempio precedente le parentesi vuote (( e )) possono essere omesse perché l'attributo non include argomenti.

public class GenericType<T>
{
   [GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
   public string Method() => default;
}

Gli argomenti di tipo generico devono soddisfare le stesse restrizioni dell'operatore typeof. I tipi che richiedono annotazioni di metadati non sono consentiti. Ad esempio, i tipi seguenti non sono consentiti come parametro di tipo generico:

  • dynamic
  • string? (o qualsiasi tipo riferimento nullable)
  • (int X, int Y) (o qualsiasi altro tipo di tupla che usa la sintassi delle tuple C#).

Questi tipi non sono rappresentati direttamente nei metadati. Includono annotazioni che descrivono il tipo. In tutti i casi, è possibile usare in alternativa il tipo sottostante:

  • object per dynamic.
  • string anziché string?.
  • ValueTuple<int, int> anziché (int X, int Y).

Supporto matematico generico

Esistono diverse funzionalità del linguaggio che consentono il supporto matematico generico:

  • Membri static virtual nelle interfacce
  • Operatori controllati definiti dall'utente
  • Operatori di spostamento relaxed
  • Operatore di spostamento a destra senza segno

È possibile aggiungere membri static abstract o static virtual nelle interfacce per definire interfacce che includono operatori che supportano l'overload, altri membri statici e proprietà statiche. Lo scenario principale per questa funzionalità consiste nell'uso di operatori matematici nei tipi generici. È ad esempio possibile implementare l'interfaccia System.IAdditionOperators<TSelf, TOther, TResult> in un tipo che implementa operator +. Altre interfacce definiscono altre operazioni matematiche o valori ben definiti. È possibile ottenere informazioni sulla nuova sintassi nell'articolo sulle interfacce. Le interfacce che includono metodi static virtual sono solitamente interfacce generiche. Inoltre, la maggior parte dichiara un vincolo in base al quale il parametro di tipo generico implementa l'interfaccia dichiarata.

Per altre informazioni e per provare la funzionalità, vedere l'esercitazione Esplorare la funzionalità C# 11 - Membri virtuali statici nelle interfacce o il post di blog sulle funzionalità di anteprima in .NET 6 (matematica generica).

La matematica generica ha creato altri requisiti per il linguaggio.

  • Operatore di spostamento a destra senza segno: nelle versioni precedenti C# 11, per forzare uno spostamento a destra senza segno, è necessario eseguire il cast di un tipo integer con segno a un tipo senza segno, eseguire lo spostamento e quindi eseguire il cast del risultato a un tipo con segno. A partire da C# 11, è possibile usare >>>, l'operatore di spostamento senza segno.
  • Requisiti degli operatori di spostamento relaxed: C# 11 rimuove il requisito in base al quale il secondo operando deve essere un int o implicitamente convertibile in int. Questa modifica consente l'uso di tipi che implementano interfacce matematiche generiche in queste posizioni.
  • Operatori checked e unchecked definiti dall'utente: gli sviluppatori possono ora definire operatori aritmetici checked e unchecked. Il compilatore genera chiamate alla variante corretta in base al contesto corrente. Per altre informazioni sugli operatori checked, vedere l'articolo sugli operatori aritmetici.

IntPtr e UIntPtr numerici

I tipi nint e nuint ora creano alias rispettivamente per System.IntPtr e System.UIntPtr.

Caratteri di nuova riga nelle interpolazioni di stringhe

Il testo all'interno dei caratteri { e } per un'interpolazione di stringhe può ora estendersi su più righe. Il testo tra i marcatori { e } viene analizzato come C#. È consentito qualsiasi carattere C# valido, incluso il carattere di nuova riga. Questa funzionalità semplifica la lettura delle interpolazioni di stringhe che usano espressioni C# più lunghe, ad esempio le espressioni switch dei criteri di ricerca o le query LINQ.

Per altre informazioni sulla funzionalità dei caratteri di nuova riga, vedere l'articolo sulle interpolazioni di stringhe nei riferimenti per il linguaggio.

Criteri elenco

I criteri di elenco estendono i criteri di ricerca per trovare corrispondenze con sequenze di elementi in un elenco o in una matrice. Ad esempio, sequence is [1, 2, 3] è true quando sequence è una matrice o un elenco di tre interi (1, 2 e 3). È possibile trovare la corrispondenza con elementi usando qualsiasi criterio, inclusi criteri di costanti, di tipo, di proprietà e relazionali. Il criterio discard (_) trova la corrispondenza con qualsiasi elemento singolo e il nuovo criterio di intervallo (..) trova la corrispondenza con qualsiasi sequenza di zero o più elementi.

Per altre informazioni sui criteri di elenco, vedere l'articolo sui criteri di ricerca nei riferimenti per il linguaggio.

Miglioramento della conversione di un gruppo di metodi in un oggetto delegato

Lo standard C# sulle conversioni dei gruppi di metodi include ora l'elemento seguente:

  • La conversione è consentita (ma non necessaria) per usare un'istanza di delegato esistente che contiene già questi riferimenti.

Le versioni precedenti dello standard impediscono al compilatore di riutilizzare l'oggetto delegato creato per la conversione di un gruppo di metodi. Il compilatore C# 11 memorizza nella cache l'oggetto delegato creato dalla conversione di un gruppo di metodi e riutilizza il singolo oggetto delegato. Questa funzionalità è stata introdotta per la prima volta in Visual Studio 2022 versione 17.2 come funzionalità di anteprima e in .NET 7 Preview 2.

Valori letterali stringa non elaborati

I valori letterali stringa non elaborati sono un nuovo formato per i valori letterali stringa. I valori letterali stringa non elaborati possono contenere testo arbitrario, inclusi spazi vuoti, nuove righe, virgolette incorporate e altri caratteri speciali senza richiedere sequenze di escape. Un valore letterale stringa non elaborato inizia con almeno tre virgolette doppie (""") e termina con lo stesso numero di virgolette doppie. In genere un valore letterale stringa non elaborato usa tre virgolette doppie su una sola riga per iniziare la stringa e tre virgolette doppie su una riga separata per terminare la stringa. I caratteri di nuova riga che seguono le virgolette di apertura e che precedono le virgolette di chiusura non sono incluse nel contenuto finale:

string longMessage = """
    This is a long message.
    It has several lines.
        Some are indented
                more than others.
    Some should start at the first column.
    Some have "quoted text" in them.
    """;

Qualsiasi spazio vuoto a sinistra delle virgolette doppie di chiusura viene rimosso dal valore letterale stringa. I valori letterali stringa non elaborati possono essere combinati con l'interpolazione di stringhe in modo da includere parentesi graffe nel testo di output. I caratteri $ indicano il numero di parentesi graffe consecutive che iniziano e terminano l'interpolazione:

var location = $$"""
   You are at {{{Longitude}}, {{Latitude}}}
   """;

L'esempio precedente specifica che due parentesi graffe iniziano e terminano un'interpolazione. Le altre parentesi graffe di apertura e chiusura sono incluse nella stringa di output.

Per altre informazioni sui valori letterali stringa non elaborati, vedere l'articolo sulle stringhe nella guida alla programmazione e gli articoli sui valori letterali stringa e sulle stringhe interpolate nei riferimenti per il linguaggio.

Struct predefinito automaticamente

Il compilatore C# 11 verifica che tutti i campi di tipo struct vengano inizializzati sul valore predefinito come parte dell'esecuzione di un costruttore. Ciò significa che qualsiasi campo o proprietà automatica non inizializzata da un costruttore viene inizializzata automaticamente dal compilatore. Gli struct in cui il costruttore non assegna specificamente tutti i campi vengono ora compilati e tutti i campi non inizializzati in modo esplicito vengono impostati sul relativo valore predefinito. Per altre informazioni su come questa modifica influisce sull'inizializzazione degli struct, vedere l'articolo sugli struct.

Applicazione dei criteri di ricerca per Span<char> o ReadOnlySpan<char> su un oggetto string costante

In diverse versioni precedenti è possibile verificare se un oggetto string ha un valore costante specifico usando i criteri di ricerca. È ora possibile usare la stessa logica basata su criteri di ricerca con variabili Span<char> o ReadOnlySpan<char>.

Ambito nameof esteso

I nomi dei parametri di tipo e i nomi dei parametri sono ora inclusi nell'ambito quando vengono usati in un'espressione nameof in una dichiarazione di attributo su tale metodo. È quindi possibile usare l'operatore nameof per specificare il nome di un parametro di un metodo in un attributo nella dichiarazione del metodo o del parametro. Questa funzionalità è molto spesso utile per aggiungere attributi per l'analisi dello stato Null.

Valori letterali stringa UTF-8

È possibile specificare il suffisso u8 su un valore letterale stringa per definire la codifica dei caratteri UTF-8. Se un'applicazione richiede stringhe UTF-8, per costanti stringa HTTP o protocolli di testo simili, è possibile usare questa funzionalità per semplificare la creazione di tali stringhe.

Per altre informazioni sui valori letterali stringa UTF-8, vedere la sezione relativa ai valori letterali stringa dell'articolo sui tipi riferimento predefiniti.

Membri obbligatori

È possibile aggiungere il modificatore required alle proprietà e ai campi per imporre a costruttori e chiamanti di inizializzare tali valori. L'attributo System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute può essere aggiunto ai costruttori per informare il compilatore che un costruttore inizializza tutti i membri obbligatori.

Per altre informazioni sui membri obbligatori, vedere la sezione init-only nell'articolo sulle proprietà.

Campi ref e variabili ref scoped

È possibile dichiarare campi ref all'interno di un oggetto ref struct. In questo modo sono supportati tipi quali System.Span<T> senza attributi speciali o tipi interni nascosti.

È possibile aggiungere il modificatore scoped a qualsiasi dichiarazione di ref, limitando così l'ambito di destinazione del riferimento.

Tipi locali di file

A partire da C# 11, è possibile usare il modificatore di accesso file per creare un tipo la cui visibilità ha come ambito il file di origine in cui è dichiarato. Questa funzionalità consente agli autori del generatore di codice sorgente di evitare conflitti di denominazione. Per altre informazioni su questa funzionalità, vedere l'articolo sui tipi con ambito file nei riferimenti per il linguaggio.

Vedi anche