Novità di C# 13
C# 13 include le nuove funzionalità seguenti. È possibile provare queste funzionalità usando la versione più recente Visual Studio 2022 o .NET 9 SDK:
-
params
raccolte -
Nuovo tipo di
lock
e semantica. -
Nuova sequenza di escape -
\e
. - Miglioramenti del tipo naturale del gruppo di metodi
- accesso implicito dell'indicizzatore negli inizializzatori di oggetti
-
Abilitare variabili locali
ref
e contestiunsafe
in iteratori e metodi asincroni -
Abilitare i tipi di
ref struct
per implementare interfacce. - Consenti tipi di struttura ref come argomenti per i parametri di tipo nei generici.
-
proprietà parziali e gli indicizzatori sono ora consentiti nei tipi di
partial
. - La priorità di risoluzione dell'overload consente agli autori delle librerie di designare un overload come migliore rispetto agli altri.
A partire da Visual Studio 17.12, C# 13 include la parola chiave contestuale field
come funzionalità di anteprima.
C# 13 è supportato in .NET 9. Per altre informazioni, vedere controllo delle versioni del linguaggio C#.
È possibile scaricare la versione più recente di .NET 9 SDK dalla pagina di download di .NET . È anche possibile scaricare Visual Studio 2022, che include .NET 9 SDK.
Le nuove funzionalità vengono aggiunte alla pagina "Novità in C#" quando sono disponibili nelle versioni di anteprima pubblica. La sezione working set della pagina di stato della funzionalità roslyn tiene traccia quando le funzionalità future vengono unite nel ramo principale.
È possibile trovare eventuali modifiche di rilievo introdotte in C# 13 nell'articolo su modifiche di rilievo.
Nota
Microsoft è interessato ai commenti e suggerimenti su queste funzionalità. Se trovi questioni con una di queste nuove funzionalità, crea un nuovo problema nel repository dotnet/roslyn.
raccolte params
Il modificatore params
non è limitato ai tipi di matrice. È ora possibile usare params
con qualsiasi tipo di raccolta riconosciuto, tra cui System.Span<T>, System.ReadOnlySpan<T>e tipi che implementano System.Collections.Generic.IEnumerable<T> e hanno un metodo Add
. Oltre ai tipi concreti, è possibile usare anche le interfacce System.Collections.Generic.IEnumerable<T>, System.Collections.Generic.IReadOnlyCollection<T>, System.Collections.Generic.IReadOnlyList<T>, System.Collections.Generic.ICollection<T>e System.Collections.Generic.IList<T> .
Quando viene usato un tipo di interfaccia, il compilatore sintetizza lo spazio di archiviazione per gli argomenti forniti. Puoi imparare di più nelle specifiche delle funzionalità per le raccolte ,params
,.
Ad esempio, le dichiarazioni di metodo possono dichiarare intervalli come parametri params
:
public void Concat<T>(params ReadOnlySpan<T> items)
{
for (int i = 0; i < items.Length; i++)
{
Console.Write(items[i]);
Console.Write(" ");
}
Console.WriteLine();
}
Nuovo oggetto blocco
Il runtime .NET 9 include un nuovo tipo per la sincronizzazione dei thread, il tipo di System.Threading.Lock. Questo tipo offre una migliore sincronizzazione dei thread tramite l'API. Il metodo Lock.EnterScope() entra in un ambito esclusivo. Il ref struct
restituito da questo supporta il modello Dispose()
per uscire dall'ambito esclusivo.
L'istruzione lock
C# riconosce se la destinazione del blocco è un oggetto Lock
. In tal caso, usa l'API aggiornata, anziché l'API tradizionale usando System.Threading.Monitor. Il compilatore riconosce anche se si converte un oggetto Lock
in un altro tipo e viene generato il codice basato sul Monitor
. Per ulteriori informazioni, consultare la specifica della funzionalità per il nuovo oggetto di blocco .
Questa funzionalità consente di ottenere i vantaggi del nuovo tipo di libreria modificando il tipo di oggetto lock
. Nessun altro codice deve cambiare.
Nuova sequenza di escape
È possibile usare \e
come carattere letterale nella sequenza di escape per il carattere ESCAPE
, Unicode U+001B
. In precedenza, è stato usato \u001b
o \x1b
. L'uso di \x1b
non è stato consigliato perché se i caratteri successivi che seguono 1b
erano cifre esadecimali valide, tali caratteri sono diventati parte della sequenza di escape.
Tipo naturale del gruppo di metodi
Questa funzionalità rende piccole ottimizzazioni per la risoluzione dell'overload che coinvolge i gruppi di metodi. Un gruppo di metodi è un metodo e tutti gli overload con lo stesso nome. Il comportamento precedente era destinato al compilatore per costruire il set completo di metodi candidati per un gruppo di metodi. Se era necessario un tipo naturale, il tipo naturale è stato determinato dal set completo di metodi candidati.
Il nuovo comportamento consiste nell'eliminare il set di metodi candidati in ogni ambito, rimuovendo i metodi candidati non applicabili. In genere, i metodi rimossi sono metodi generici con l'arità errata o vincoli che non sono soddisfatti. Il processo continua all'ambito esterno successivo solo se non vengono trovati metodi candidati. Questo processo segue più da vicino l'algoritmo generale per la risoluzione dell'overload. Se tutti i metodi candidati trovati in un determinato ambito non corrispondono, il gruppo di metodi non ha un tipo naturale.
È possibile leggere i dettagli delle modifiche nella specifica della proposta .
Accesso implicito all'indice
L'operatore di indice implicito "from the end", ^
, è ora consentito in un'espressione di inizializzazione di un oggetto. Ad esempio, è ora possibile inizializzare una matrice in un inizializzatore di oggetto, come illustrato nel codice seguente:
public class TimerRemaining
{
public int[] buffer { get; set; } = new int[10];
}
var countdown = new TimerRemaining()
{
buffer =
{
[^1] = 0,
[^2] = 1,
[^3] = 2,
[^4] = 3,
[^5] = 4,
[^6] = 5,
[^7] = 6,
[^8] = 7,
[^9] = 8,
[^10] = 9
}
};
La classe TimerRemaining
include una matrice buffer
inizializzata a una lunghezza di 10. Nell'esempio precedente vengono assegnati valori a questa matrice usando l'operatore di indice "from the end" (^
), creando in modo efficace una matrice che conta da 9 a 0.
Nelle versioni precedenti a C# 13, l'operatore ^
non può essere usato in un inizializzatore di oggetto. È necessario indicizzare gli elementi dalla parte anteriore.
ref
e unsafe
negli iteratori e async
nei metodi
Questa funzionalità e le due funzionalità seguenti consentono ai tipi di ref struct
di usare nuovi costrutti. Questi tipi non verranno usati a meno che tu non scriva tipi di ref struct
personalizzati. È più probabile che si noterà un vantaggio indiretto man mano che System.Span<T> e System.ReadOnlySpan<T> ottengono più funzionalità.
Prima di C# 13, i metodi iteratori (metodi che usano yield return
) e async
metodi non potevano dichiarare variabili di ref
locali, né potevano avere un contesto unsafe
.
In C# 13 i metodi async
possono dichiarare ref
variabili locali o variabili locali di un tipo ref struct
. Tuttavia, tali variabili non possono essere accessibili attraverso un limite di await
. Né possono essere accessibili attraverso un limite di yield return
.
Questa restrizione rilassata consente al compilatore di consentire un uso verificabile e sicuro di ref
variabili locali e ref struct
tipi in più posizioni. È possibile usare in modo sicuro tipi come System.ReadOnlySpan<T> in questi metodi. Il compilatore indica se si violano le regole di sicurezza.
Allo stesso modo, C# 13 consente i contesti unsafe
nei metodi di iterazione. Tuttavia, tutte le istruzioni yield return
e yield break
devono essere in contesti sicuri.
allows ref struct
Prima di C# 13, ref struct
tipi non potevano essere dichiarati come argomento di tipo per un tipo o un metodo generico. Ora, le dichiarazioni di tipo generico possono aggiungere un anti-vincolo, allows ref struct
. Questo anti-vincolo dichiara che l'argomento di tipo fornito per tale parametro di tipo può essere un tipo ref struct
. Il compilatore applica le regole di sicurezza dei riferimenti a tutte le istanze del parametro di tipo.
Ad esempio, è possibile dichiarare un tipo generico come il codice seguente:
public class C<T> where T : allows ref struct
{
// Use T as a ref struct:
public void M(scoped T p)
{
// The parameter p must follow ref safety rules
}
}
In questo modo è possibile usare tipi come System.Span<T> e System.ReadOnlySpan<T> con algoritmi generici, ove applicabile. Per altre informazioni, vedere gli aggiornamenti per where
e l'articolo della guida alla programmazione sui vincoli generici .
ref struct
interfacce
Prima di C# 13, i tipi ref struct
non erano autorizzati a implementare le interfacce. A partire da C# 13, essi possono. È possibile dichiarare che un tipo di ref struct
implementa un'interfaccia. Tuttavia, per garantire regole di sicurezza di riferimento, un tipo di ref struct
non può essere convertito in un tipo di interfaccia. Questa è una conversione di boxing e potrebbe compromettere la sicurezza dei riferimenti. È possibile accedere alle dichiarazioni esplicite dei metodi di interfaccia in un ref struct
solo tramite un parametro di tipo in cui tale parametro di tipo allows ref struct
. Inoltre, ref struct
tipi devono implementare tutti i metodi dichiarati in un'interfaccia, inclusi i metodi con un'implementazione predefinita.
Altre informazioni sugli aggiornamenti sui tipi di ref struct
e sull'aggiunta del vincolo generico allows ref struct
.
Più membri parziali
È possibile dichiarare le proprietà partial
e gli indicizzatori partial
in C# 13. Le proprietà parziali e gli indicizzatori seguono in genere le stesse regole dei metodi di partial
: si crea una dichiarazione dichiarante e una che implementa la dichiarazione. Le firme delle due dichiarazioni devono corrispondere. Una restrizione è che non è possibile usare una dichiarazione di proprietà automatica per l'implementazione di una proprietà parziale. Le proprietà che non dichiarano un corpo vengono considerate le dichiarazioni dichiaranti.
public partial class C
{
// Declaring declaration
public partial string Name { get; set; }
}
public partial class C
{
// implementation declaration:
private string _name;
public partial string Name
{
get => _name;
set => _name = value;
}
}
Puoi ottenere maggiori informazioni nell'articolo sui membri parziali .
Priorità di risoluzione dell'overload
In C# 13 il compilatore riconosce il OverloadResolutionPriorityAttribute per preferire un overload rispetto a un altro. Gli autori di librerie possono usare questo attributo per garantire che un overload nuovo e migliore sia preferibile rispetto a un overload esistente. Ad esempio, è possibile aggiungere un nuovo overload più efficiente. Non si vuole interrompere il codice esistente che usa la libreria, ma si vuole che gli utenti vengano aggiornati alla nuova versione quando ricompilano. È possibile usare priorità di risoluzione dell'overload per informare il compilatore quale overload debba essere preferito. I sovraccarichi con la priorità più alta sono preferiti.
Questa funzionalità è destinata agli autori di librerie per evitare ambiguità quando si aggiungono nuovi overload. Gli autori della libreria devono prestare attenzione a questo attributo per evitare confusione.
Parola chiave field
La parola chiave contestuale field
si trova in C# 13 come funzionalità di anteprima. Il token field
accede al campo sottostante sintetizzato dal compilatore in una funzione di accesso alle proprietà. Consente di scrivere un corpo di un accessore senza dichiarare un campo di supporto esplicito nella dichiarazione di tipo. È possibile dichiarare un corpo per una o entrambe le funzioni di accesso per una proprietà supportata dal campo.
La funzionalità field
viene rilasciata come funzionalità di anteprima. Vogliamo imparare dalle vostre esperienze usandolo. Esiste una potenziale modifica o confusione durante la lettura del codice nei tipi che includono anche un campo denominato field
. È possibile usare @field
o this.field
per evitare ambiguità tra la parola chiave field
e l'identificatore.
Importante
La parola chiave field
è una funzionalità di anteprima in C# 13. È necessario usare .NET 9 e impostare l'elemento <LangVersion>
su preview
nel file di progetto per usare la parola chiave contestuale field
.
È consigliabile prestare attenzione usando la funzionalità di parola chiave field
in una classe con un campo denominato field
. La nuova parola chiave field
oscura un campo denominato field
nell'ambito della funzione di accesso della proprietà. È possibile modificare il nome della variabile di field
oppure usare il token di @
per fare riferimento all'identificatore field
come @field
. Per saperne di più, leggi il documento di specifica della funzionalità per la parola chiave field
.
Se provi questa funzionalità e hai commenti o suggerimenti, aggiungili alla segnalazione numero nel repository csharplang
.