Novità in C# 10

C# 10 aggiunge le funzionalità e i miglioramenti seguenti al linguaggio C#:

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 ToStringsealed 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.