Le novità di C# 11 e C# 12 spiegate bene: produttività, performance e sintassi moderna

Le novità di C# 11 e C# 12 spiegate bene: produttività, performance e sintassi moderna

Marco Puccio

Novità in C# 11 e C# 12: le funzionalità più utili per scrivere codice moderno

Negli ultimi anni, il linguaggio C# ha compiuto passi da gigante nel miglioramento della produttività degli sviluppatori e nella semplificazione della scrittura di codice più sicuro, performante e leggibile. Con le versioni C# 11 e C# 12, Microsoft ha introdotto nuove funzionalità che rappresentano un'importante evoluzione del linguaggio. In questo articolo andremo ad analizzare le principali novità, corredate da esempi pratici e riflessioni su come possano essere utilmente integrate nei progetti reali.


1. Required Members (C# 11)

La keyword required permette di indicare che una proprietà deve obbligatoriamente essere inizializzata prima della fine del costruttore o dell'inizializzazione di un oggetto. Questo consente di definire classi più robuste evitando che alcuni campi critici vengano dimenticati o lasciati a null.

public class Utente
{
    public required string Nome { get; init; }
    public required string Cognome { get; init; }
}

var utente = new Utente { Nome = "Mario", Cognome = "Rossi" }; // OK

Se si omette l'inizializzazione di un campo required, il compilatore genererà un errore.

Perché è utile:

  • Elimina la necessità di costruttori complessi solo per forzare l'inizializzazione.

  • Migliora la leggibilità e la sicurezza del codice.

  • Ideale per modelli in API REST, DTO, e oggetti immutabili.


2. Primary Constructors (C# 12)

I Primary Constructor, già presenti nei record, ora possono essere utilizzati anche nelle classi. Consentono di dichiarare i parametri del costruttore direttamente nella dichiarazione della classe, e accedervi nei membri della classe.

public class Persona(string nome, string cognome)
{
    public void Saluta() => Console.WriteLine($"Ciao {nome} {cognome}!");
}

Perché è utile:

  • Riduce drasticamente il boilerplate.

  • Consente una scrittura chiara e immediata dei dati essenziali della classe.

  • Perfetto per modelli ViewModel, Controller, e classi di servizio leggere.


3. Collection Expressions (C# 12)

Con la sintassi [..], è ora possibile inizializzare collezioni in modo molto più compatto e leggibile. È supportato anche lo spread operator (..) per unire più liste.

var lista = [1, 2, 3];
var unione = [..lista, 4, 5];

Perché è utile:

  • Sintassi più espressiva e moderna per l'inizializzazione di array e liste.

  • Ottimo per scenari con dati predefiniti o dinamici.

  • Riduce la verbosità nella preparazione di dati statici.


4. Interpolated String Handlers (C# 10+)

C# ha introdotto un nuovo modo per gestire le interpolated strings con maggiore efficienza. Questa feature consente di ottimizzare le stringhe interpolated in base al contesto, ad esempio nei log, evitando la creazione di stringhe se non necessarie.

logger.LogDebug($"Utente {utente.Id} - {utente.Email}");

Perché è utile:

  • Aumenta le performance evitando allocazioni inutili.

  • Ideale nei contesti in cui si generano molte stringhe condizionate (log, diagnostica).

  • Consente di scrivere interpolated string handler personalizzati per controllare meglio il comportamento.


5. Default Lambda Parameters (C# 12)

Una delle funzionalità più richieste: la possibilità di dichiarare parametri con valore di default nelle espressioni lambda.

Func<int, int, int> somma = (a, b = 0) => a + b;
Console.WriteLine(somma(5)); // 5

Perché è utile:

  • Rende le lambda più flessibili.

  • Evita la necessità di overload separati per gestire comportamenti alternativi.

  • Ottimo per funzioni inline, parametri di callback, e metodi di estensione.


6. Ref readonly e Scoped Parameters (C# 11-12)

C# continua a raffinare la gestione efficiente della memoria con l'introduzione di ref readonly e scoped. Queste keyword sono fondamentali per chi lavora con struct o tipi pesanti da copiare.

public void Stampa(ref readonly int valore)
{
    Console.WriteLine(valore);
}

ref readonly impedisce la modifica del valore e assicura che venga passato per riferimento. scoped invece aiuta a limitare la vita di una variabile, prevenendo il ritorno di riferimenti non sicuri.

Perché è utile:

  • Prestazioni superiori in scenari ad alto carico.

  • Riduce il numero di copie implicite dei dati.

  • Fondamentale in contesti ad alte performance come game engine o elaborazione dati.


Conclusioni

Le nuove funzionalità introdotte con C# 11 e C# 12 non sono semplici migliorie estetiche, ma strumenti concreti per aumentare la produttività, la sicurezza e l'efficienza del codice. Dalla semplificazione dei costruttori, all'inizializzazione delle collezioni, fino alla gestione avanzata della memoria e delle stringhe, queste novità offrono vantaggi tangibili per ogni sviluppatore.

Se stai iniziando un nuovo progetto o vuoi rinnovare una codebase esistente, è il momento ideale per integrare queste nuove feature e trarne beneficio fin da subito.