Condividi tramite


Novità di C# 14

C# 14 include le nuove funzionalità seguenti. È possibile provare queste funzionalità usando la versione più recente di Visual Studio 2022 o .NET 10 SDK:

C# 14 è supportato in .NET 10. Per ulteriori informazioni, vedere versionamento del linguaggio C#.

È possibile scaricare la versione più recente di .NET 10 SDK dalla pagina di download di .NET. È anche possibile scaricare Visual Studio 2022, che include .NET 10 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. Questo articolo è stato aggiornato per .NET 10 Preview 1.

È possibile trovare eventuali modifiche di rilievo introdotte in C# 14 nell'articolo sulle modifiche di rilievo.

Annotazioni

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.

Membri dell'estensione

C# 14 aggiunge una nuova sintassi per definire i membri dell'estensione. La nuova sintassi consente di dichiarare proprietà di estensione oltre ai metodi di estensione. È anche possibile dichiarare membri di estensione che estendono il tipo, anziché un'istanza del tipo. In altre parole, questi nuovi membri di estensione possono essere visualizzati come membri statici del tipo che estendi. L'esempio di codice seguente illustra un esempio dei diversi tipi di membri di estensione che è possibile dichiarare:

public static class Enumerable
{
    // Extension block
    extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>
    {
        // Extension property:
        public bool IsEmpty => !source.Any();
        // Extension indexer:
        public TSource this[int index] => source.Skip(index).First();

        // Extension method:
        public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }
    }

    // extension block, with a receiver type only
    extension<TSource>(IEnumerable<TSource>) // static extension members for IEnumerable<Source>
    {
        // static extension method:
        public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) { ... }

        // static extension property:
        public static IEnumerable<TSource> Identity => Enumerable.Empty<TSource>();
    }
}

I membri nel primo blocco di estensione vengono chiamati come se fossero membri dell'istanza di IEnumerable<TSource>, ad esempio sequence.IsEmpty. I membri nel secondo blocco di estensione vengono chiamati come se fossero membri statici di IEnumerable<TSource>, ad esempio IEnumerable<int>.Identity.

Per altre informazioni, leggere l'articolo sui membri dell'estensione nella guida alla programmazione, l'articolo di riferimento sul linguaggio sulla extension parola chiave e la specifica delle funzionalità per la nuova funzionalità dei membri dell'estensione.

Parola chiave field

Il token field consente di scrivere un corpo della funzione di accesso alle proprietà senza dichiarare un campo sottostante esplicito. Il token field viene sostituito con un campo sottostante sintetizzato dal compilatore.

Ad esempio, in precedenza, se si vuole assicurarsi che una string proprietà non possa essere impostata su null, è necessario dichiarare un campo sottostante e implementare entrambe le funzioni di accesso:

private string _msg;
public string Message
{
    get => _msg;
    set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}

È ora possibile semplificare il codice per:

public string Message
{
    get;
    set => field = value ?? throw new ArgumentNullException(nameof(value));
}

È possibile dichiarare un corpo per una o entrambe le funzioni di accesso per una proprietà supportata dal campo.

C'è la possibilità di un cambiamento significativo o confusione nella lettura del codice nei tipi che includono anche un simbolo denominato field. È possibile usare @field o this.field per disambiguare tra la field parola chiave e l'identificatore oppure rinominare il simbolo corrente field per fornire una distinzione migliore.

Se si prova questa funzionalità e si hanno commenti e suggerimenti, commentare il problema di funzionalità nel csharplang repository.

La parola chiave contestuale field si trova in C# 13 come funzionalità di anteprima.

Conversioni implicite dell'intervallo

C# 14 introduce il supporto di prima classe per System.Span<T> e System.ReadOnlySpan<T> nel linguaggio. Questo supporto prevede nuove conversioni implicite che consentono una programmazione più naturale con questi tipi.

Span<T> e ReadOnlySpan<T> vengono usati in molti modi chiave in C# e nel runtime. L'introduzione migliora le prestazioni senza rischiare la sicurezza. C# 14 riconosce la relazione e supporta alcune conversioni tra ReadOnlySpan<T>, Span<T>e T[]. I tipi span possono essere ricevitori di metodi di estensione, comporre con altre conversioni e semplificare gli scenari di inferenza dei tipi generici.

È possibile trovare l'elenco delle conversioni implicite nell'intervallo nell'articolo sui tipi predefiniti nella sezione delle informazioni di riferimento sul linguaggio. Puoi ottenere ulteriori dettagli leggendo la specifica della funzionalità per i tipi di intervallo di prima classe.

Tipi generici non associati e nameof

A partire da C# 14, l'argomento a nameof può essere un tipo generico non vincolato. Ad esempio, nameof(List<>) restituisce List. Nelle versioni precedenti di C# è possibile usare solo tipi generici chiusi, ad esempio List<int>, per restituire il List nome.

Semplici parametri lambda con modificatori

È possibile aggiungere modificatori di parametri, ad esempio scoped, refin, out, o ref readonly ai parametri dell'espressione lambda senza specificare il tipo di parametro:

delegate bool TryParse<T>(string text, out T result);
// ...
TryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);

In precedenza, l'aggiunta di eventuali modificatori era consentita solo quando le dichiarazioni di parametro includevano i tipi per i parametri. La dichiarazione precedente richiede i tipi in tutti i parametri:

TryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);

Il params modificatore richiede comunque un elenco di parametri tipizzato in modo esplicito.

Per altre informazioni su queste modifiche, vedere l'articolo sulle espressioni lambda nelle informazioni di riferimento sul linguaggio C#.

Più membri parziali

È ora possibile dichiarare costruttori di istanza ed eventi come membri parziali.

I costruttori parziali e gli eventi parziali devono includere esattamente una dichiarazione di definizione e una dichiarazione di implementazione.

Solo la dichiarazione di implementazione di un costruttore parziale può includere un inizializzatore del costruttore: this() o base(). Una sola dichiarazione di tipo parziale può includere la sintassi del costruttore primario.

La dichiarazione di implementazione di un evento parziale deve includere gli accessori add e remove. La dichiarazione di definizione dichiara un evento simile a un campo.

Assegnazione composta definita dall'utente

Per altre informazioni, vedere la specifica delle funzionalità per l'assegnazione composta definita dall'utente.

Assegnazione null-condizionale

Gli operatori di accesso ai membri condizionali Null, ?. e ?[], ora possono essere usati sul lato sinistro di un'assegnazione semplice o composta.

Prima di C# 14, era necessario verificare la presenza di valori nulli in una variabile prima di assegnarla a una proprietà.

if (customer is not null)
{
    customer.Order = GetCurrentOrder();
}

È possibile semplificare il codice precedente usando l'operatore ?. :

customer?.Order = GetCurrentOrder();

Il lato destro dell'operatore = viene valutato solo quando il lato sinistro non è Null. Se customer è Null, il codice non chiama GetCurrentOrder.

Oltre all'assegnazione, è possibile usare operatori di accesso ai membri condizionali al valore null con operatori di assegnazione composta (+=, -= e altri). Tuttavia, l'incremento e il decremento e ++--, non sono consentiti.

Per altre informazioni, vedere l'articolo di riferimento sul linguaggio sull'accesso ai membri condizionali e la specifica della funzionalità per l'assegnazione condizionale Null.

Vedere anche