Novità in C# 10
C# 10 aggiunge le funzionalità e i miglioramenti seguenti al linguaggio C#:
- Struct di record
- Miglioramenti dei tipi di struttura
- Gestori di stringhe interpolate
- Direttive
global using
- Dichiarazione di namespace con ambito file
- Criteri di proprietà estesi
- Miglioramenti delle espressioni lambda
- Possibilità di usare stringhe
const
interpolate - Sealing di
ToString()
per i tipi record - Assegnazione definita migliorata
- Assegnazione e dichiarazione nella stessa decostruzione
- Possibilità di applicare l'attributo
AsyncMethodBuilder
ai metodi - Attributo CallerArgumentExpression
- Pragma
#line
avanzato - Ciclo di avviso 6
C# 10 è supportato in .NET 6. Per altre informazioni, vedere controllo delle versioni del linguaggio C#.
È possibile scaricare la versione più recente di .NET 6 SDK dalla pagina dei download di .NET. È anche possibile scaricare Visual Studio 2022, che include .NET 6 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.
Struct di record
È possibile dichiarare record di tipo valore usando le dichiarazioni di record struct
o readonly record struct
. È ora possibile chiarire che un record
è un tipo riferimento con la dichiarazione di record class
.
Miglioramenti dei tipi di struttura
C# 10 introduce i miglioramenti seguenti in relazione ai tipi di struttura:
- È possibile dichiarare un costruttore senza parametri di istanza in un tipo di struttura e inizializzare un campo o una proprietà dell'istanza nella relativa dichiarazione. Per altre informazioni, vedere la sezione Inizializzazione Struct e valori predefiniti dell'articolo Tipi di struttura.
- Un operando a sinistra dell'espressione
with
può essere di qualsiasi tipo di struttura o di tipo (riferimento) anonimo.
Gestore di stringhe interpolate
È possibile creare un tipo che genera la stringa risultante da un'espressione di stringa interpolata. Le librerie .NET usano questa funzionalità in molte API. È possibile crearne una seguendo questa esercitazione.
Direttive using globali
È possibile aggiungere il modificatore global
a qualsiasi direttiva using per indicare al compilatore che la direttiva si applica a tutti i file di origine nella compilazione, che in genere corrispondono a tutti i file di origine in un progetto.
Dichiarazione di namespace con ambito file
È possibile usare una nuova forma della dichiarazione di namespace
per dichiarare che tutte le dichiarazioni che seguono sono membri dello spazio dei nomi dichiarato:
namespace MyNamespace;
Questa nuova sintassi consente di risparmiare spazio orizzontale e verticale per le dichiarazioni di namespace
.
Criteri di proprietà estesi
A partire da C# 10, è possibile fare riferimento a proprietà o campi annidati all'interno di un criterio di proprietà. Ad esempio, un criterio nel formato
{ Prop1.Prop2: pattern }
è valido in C# 10 e versioni successive ed è equivalente a
{ Prop1: { Prop2: pattern } }
che è valido in C# 8.0 e versioni successive.
Per altre informazioni, vedere la nota sulla proposta di funzionalità Criteri di proprietà estesi. Per altre informazioni su un criterio di proprietà, vedere la sezione Criterio di proprietà dell'articolo Criteri.
Miglioramenti delle espressioni lambda
C# 10 include numerosi miglioramenti alla gestione delle espressioni lambda:
- Le espressioni lambda possono avere un tipo naturale, dove il compilatore può dedurre un tipo delegato dall'espressione lambda o dal gruppo di metodi.
- Le espressioni lambda possono dichiarare un tipo restituito quando il compilatore non può dedurlo.
- Alle espressioni lambda possono essere applicati attributi.
Queste funzionalità rendono le espressioni lambda più simili ai metodi e alle funzioni locali. Semplificano l'uso delle espressioni lambda senza dichiarare una variabile di un tipo delegato e interagiscono più facilmente con le nuove API minime di ASP.NET Core.
Stringhe costanti interpolate
In C# 10 le stringhe const
possono essere inizializzate usando l'interpolazione di stringhe se tutti i segnaposto sono stringhe costanti. L'interpolazione può creare stringhe più leggibili durante la compilazione delle stringhe costanti usate nell'applicazione. Le espressioni segnaposto non possono essere costanti numeriche perché tali costanti vengono convertite in stringhe in fase di esecuzione. Le impostazioni cultura correnti possono influire sulla rappresentazione delle stringhe. Per altre informazioni, vedere l'articolo sulle espressioni const
nei riferimenti per il linguaggio.
Sealing di ToString per i tipi record
In C# 10 è possibile aggiungere il modificatore sealed
quando si esegue l'override di ToString
in un tipo record. Il sealing del metodo ToString
impedisce al compilatore di sintetizzare un metodo ToString
per qualsiasi tipo record derivato. Un metodo ToString
sealed
assicura che tutti i tipi record derivati usino il metodo ToString
definito in un tipo record di base comune. Per altre informazioni su questa funzionalità, vedere l'articolo sui record.
Assegnazione e dichiarazione nella stessa decostruzione
Questa modifica rimuove una limitazione dalle versioni precedenti di C#. Nelle versioni precedenti, una decostruzione può assegnare tutti i valori alle variabili esistenti oppure può inizializzare le nuove variabili dichiarate:
// Initialization:
(int x, int y) = point;
// assignment:
int x1 = 0;
int y1 = 0;
(x1, y1) = point;
C# 10 rimuove questa limitazione:
int x = 0;
(x, int y) = point;
Assegnazione definita migliorata
Nelle versioni precedenti C# 10 si verificano molti scenari in cui l'assegnazione definita e l'analisi dello stato Null generano avvisi che risultano falsi positivi. Si tratta in genere di scenari che implicano confronti con costanti booleane, l'accesso a una variabile solo in true
o false
in un'istruzione if
ed espressioni null coalescing. Questi esempi generano avvisi nelle versioni precedenti di C#, ma non in C# 10:
string representation = "N/A";
if ((c != null && c.GetDependentValue(out object obj)) == true)
{
representation = obj.ToString(); // undesired error
}
// Or, using ?.
if (c?.GetDependentValue(out object obj) == true)
{
representation = obj.ToString(); // undesired error
}
// Or, using ??
if (c?.GetDependentValue(out object obj) ?? false)
{
representation = obj.ToString(); // undesired error
}
Il principale effetto di questo miglioramento è che gli avvisi per l'assegnazione definita e l'analisi dello stato Null sono più accurati.
Possibilità di applicare l'attributo AsyncMethodBuilder ai metodi
In C# 10 e versioni successive è possibile specificare un generatore di metodi asincroni diverso per un singolo metodo, oltre a definire il tipo di generatore per tutti i metodi che restituiscono un determinato tipo simile ad attività. Un generatore di metodi asincroni personalizzato consente scenari avanzati di ottimizzazione delle prestazioni in cui un determinato metodo può trarre vantaggio da un generatore personalizzato.
Per altre informazioni, vedere la sezione su AsyncMethodBuilder
nell'articolo sugli attributi letti dal compilatore.
Diagnostica dell'attributo CallerArgumentExpression
È possibile utilizzare l'attributo System.Runtime.CompilerServices.CallerArgumentExpressionAttribute per specificare un parametro sostituito dal compilatore con la rappresentazione testuale di un altro argomento. Questa funzionalità consente alle librerie di creare una diagnostica più specifica. Il codice seguente verifica una condizione. Se la condizione è false, il messaggio di eccezione contiene la rappresentazione testuale dell'argomento passato a condition
:
public static void Validate(bool condition, [CallerArgumentExpression("condition")] string? message=null)
{
if (!condition)
{
throw new InvalidOperationException($"Argument failed validation: <{message}>");
}
}
Per altre informazioni su questa funzionalità, vedere l'articolo sugli attributi delle informazioni sul chiamante nella sezione di riferimento per il linguaggio.
Pragma #line avanzato
C# 10 supporta un nuovo formato per il pragma #line
. Probabilmente non è necessario usare il nuovo formato, ma è possibile osservarne gli effetti. I miglioramenti consentono un output più dettagliato in linguaggi specifici di dominio come Razor. Il motore Razor usa questi miglioramenti per migliorare l'esperienza di debug. I debugger possono infatti evidenziare il codice sorgente Razor in modo più accurato. Per altre informazioni sulla nuova sintassi, vedere l'articolo sulle direttive del preprocessore nei riferimenti per il linguaggio. È anche possibile leggere l'articolo specifico su questa funzionalità per esempi basati su Razor.