Le novità di C# 8

di Cristian Civera, in C#,

C# è il linguaggio di riferimento per quanto riguarda il mondo Microsoft .NET. E' nato con esso e ad ogni rilascio di Visual Studio spesso si rinnova con nuove funzionalità. Anche con l'uscita di Visual Studio 2019 troviamo disponibile il supporto ad una nuova versione di questo linguaggio, ormai giunto alla versione 8. In realtà il supporto è ancora beta, va abilitato manualmente e, come ormai consuetudine, diventerà definitivo tramite aggiornamenti che frequentemente escono per l'IDE di Microsoft.

L'uscita di C# 8 è quindi un po' in ritardo rispetto all'ambiente di sviluppo, ma tutto ciò è dovuto alla non disponibilità di .NET Core 3, la prossima versione prevista per settembre. C# 8 introduce interessanti novità per certi versi anche impattanti e contrariamente al passato non si limita più ad essere una funzionalità del compilatore applicabile a qualsiasi versione del .NET Framework o di .NET Core, ma vi è un'esplicita dipendenza con .NET Core 3. Più precisamente, alcune caratteristiche restano dei meri shortcut di scrittura, mentre altre richiedono un runtime o tipi specifici di appoggio. Possiamo quindi teoricamente usare C# 8 anche su "vecchi" runtime, ma per goderne appieno le funzionalità dobbiamo necessariamente usare .NET Core 3 che, al momento della stesura dell'articolo, è attualmente in preview. E' per certi versi una forte limitazione, ma è anche vero che parallelamente .NET Core 3 supporta anche le applicazioni desktop con qualsiasi framework di UI utilizzato. L'intento è quindi quello di spingerci verso la migrazione a .NET Core, anche al di fuori del mondo web, e sfruttare il fatto che ogni applicativo può beneficiare del runtime che necessità senza obbligare le macchine ad avere certi requisiti.

Sebbene il progetto del linguaggio sia open source e fiocca di proposte al linguaggio, Microsoft si muove molto lentamente al fine di introdurre poche, ma utili funzioni a C# per tenerlo al passo con i tempi, ma senza snaturarlo. In questo articolo vogliamo quindi analizzare tutte le nuove funzionalità introdotte, partendo da quella che probabilmente è la più importante e significativa rispetto alle altre: i nullable reference type.

Nullable reference type

Nel mondo .NET sappiamo che ogni oggetto che andiamo ad utilizzare può essere di due tipi: di valore o di riferimento. I primi sono rappresentati dai tipi primitivi, come numeri, le date e più in generale le strutture. Risiedono nello stack e hanno sempre un valore, anche se una costante predefinita. I tipi di riferimento, invece, come stringhe e tutte le classi, vanno istanziate nel managed heap e il loro riferimento mantenuto tramite una variabile che però può assumere un valore nullo. Avere una variabile a null vuol dire non puntare a nessuno oggetto, ma vuol dire anche dare un significato alla variabile stessa che varia a seconda delle situazioni. Molto spesso usiamo questa tecnica per restituire un oggetto da una funzione e interpretiamo il null come "il record non esiste", "l'operazione non può essere effettuata" o "qualcosa è andato storto". Queste interpretazioni rappresentano un uso improprio dei tipi di riferimento, perché molto spesso ci sono strumenti più adeguati, come le eccezioni, oppure gli special case. Prendiamo in esame il seguente codice.

// Creo un nuovo ordine
var order = new Order();
Console.WriteLine($"Order {order.Id.ToUpper()}");

// Aggiungo una riga
var item = new OrderItem(12);
order.Items.Add(item);

Tralasciando le logiche delle classi Order e OrderItem e le eventuali eccezioni che giustamente potrebbero lanciare, nell'usare la classe Order stiamo dando per scontato che le proprietà Id, che stampiamo a video, e la proprietà Items, sulla quale aggiungiamo una riga, non siano nulle. Se così non fosse a runtime incontreremmo l'odiosissima NullReferenceException, in molti casi anche difficile da diagnosticare se non disponiamo dei simboli. La classe in questione potrebbe essere stata scritta in questo modo.

public class Order
{
    public string Id { get; set; }

    public List<OrderItem> Items { get; set; }
}

La pigrizia spesso fa da padrone e ci spingerebbe a scrivere questa classe così, senza sfruttare appieno le potenzialità della programmazione ad oggetti. Non c'è in realtà nulla che ci garantisce come utilizzare al meglio la classe: né il compilatore, né l'IDE. Sono le convenzioni e le buone regole di scrittura che fanno sì che ogni volta che usiamo una libreria o una classe della Base Class Library non dobbiamo porci problemi sulla nullabilità delle variabili. Queste convenzioni ci evitano di dover riempire il codice di if che valutino la nullabilità, creino comportamenti diversi e spargendo logiche per tutta la soluzione. Otteniamo così codice meno leggibile e più a rischio bug.

C# 8 per risolvere il problema propone di invertire l'approccio. Su nuovi progetti troveremo un nuovo flag NullableContextOptions attivo e su quelli già esistenti ci basta aggiungerlo manualmente direttamente nel file csproj.

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <LangVersion>8.0</LangVersion>
        <NullableContextOptions>enable</NullableContextOptions>
    </PropertyGroup>

Nel fare questo appena compiliamo troviamo una serie di warning e l'IDE che li segnala.

7 pagine in totale: 1 2 3 4 5 6 7
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Top Ten Articoli

Articoli via e-mail

Iscriviti alla nostra newsletter nuoviarticoli per ricevere via e-mail le notifiche!

In primo piano

I più letti di oggi

In evidenza

Misc