Come usare l'immutabilità in C #

L'immutabilità è una caratteristica dei linguaggi di programmazione funzionale che rende i programmi più facili da scrivere, testare e mantenere. Tuttavia, l'immutabilità non è supportata da molti linguaggi di programmazione imperativi. Fino a poco tempo, C # non supportava l'immutabilità out-of-the-box. 

Ciò cambia con l'introduzione dei record in C # 9, disponibile per l'anteprima in .NET 5. Tuttavia, è possibile implementare l'immutabilità nelle versioni precedenti di C # utilizzando lo spazio dei nomi System.Collections.Immutable, disponibile come pacchetto NuGet. 

Un oggetto immutabile è definito come un oggetto che non può essere modificato dopo essere stato creato. Per molti casi d'uso, come gli oggetti di trasferimento dati, l'immutabilità è una caratteristica desiderabile. In questo articolo viene illustrato il motivo per cui potremmo voler sfruttare l'immutabilità e come implementare l'immutabilità in C #.

Per lavorare con gli esempi di codice forniti in questo articolo, dovresti avere Visual Studio 2019 installato nel tuo sistema. Se non hai già una copia, puoi scaricare Visual Studio 2019 qui. 

Creare un progetto di applicazione console .NET Core in Visual Studio

Prima di tutto, creiamo un progetto di applicazione console .NET Core in Visual Studio. Supponendo che Visual Studio 2019 sia installato nel sistema, seguire i passaggi descritti di seguito per creare un nuovo progetto di applicazione console .NET Core in Visual Studio.

  1. Avvia l'IDE di Visual Studio.
  2. Fai clic su "Crea nuovo progetto".
  3. Nella finestra "Crea nuovo progetto", seleziona "App Console (.NET Core)" dall'elenco dei modelli visualizzati.
  4. Fare clic su Avanti. 
  5. Nella finestra "Configura il tuo nuovo progetto" mostrata di seguito, specifica il nome e la posizione per il nuovo progetto.
  6. Fare clic su Crea. 

Questo creerà un nuovo progetto di applicazione console .NET Core in Visual Studio 2019. Useremo questo progetto per illustrare l'immutabilità nelle sezioni successive di questo articolo.

Installa il pacchetto NuGet System.Collection.Immutable

Per lavorare con i tipi non modificabili, è necessario installare il pacchetto System.Collections.Immutable da NuGet. Puoi farlo tramite il gestore di pacchetti NuGet all'interno dell'IDE di Visual Studio 2019 o eseguendo il comando seguente nella console del gestore di pacchetti NuGet:

Install-Package System.Collections.Immutable

Questo pacchetto comprende una raccolta di classi thread-safe, note anche come raccolte immutabili.

Comprendere l'immutabilità e i record in C # 9

Un oggetto di trasferimento dati è un classico esempio di quando si desidera l'immutabilità. Un'istanza di un DTO è spesso serializzata in modo che possa essere indipendente dalla tecnologia utilizzata al consumatore. Naturalmente, quando si trasferisce un oggetto dati tra un database e un client, si desidera garantire che l'oggetto non possa essere modificato - e questo è esattamente lo scopo di un DTO. Puoi leggere ulteriori informazioni sull'uso degli oggetti di trasferimento dati in C # dal mio precedente articolo qui. 

Per creare DTO immutabili, puoi sfruttare un ReadOnlyCollection o i tipi di raccolta immutabili thread-safe nello spazio dei nomi System.Collections.Immutable. In alternativa, è possibile sfruttare i tipi di record in C # 9 per implementare DTO non modificabili.

Un tipo di record in C # 9 è un tipo di dati leggero e non modificabile (o una classe leggera) con proprietà di sola lettura. Poiché un tipo di record è immutabile, è thread-safe e non può essere modificato o modificato dopo essere stato creato.

È possibile inizializzare un tipo di record solo all'interno di un costruttore. La creazione di un tipo di record per una classe (Autore in questo esempio) è semplice come il seguente frammento di codice.

dati della classe Autore (int Id, string firstName, string lastName, string address);

Puoi anche scrivere il tipo di record Autore come mostrato nello snippet di codice riportato di seguito:

public data class Autore {

    public int Id {get; dentro; }

    public string firstName {get; dentro; }

    stringa pubblica lastName {get; dentro; }

    indirizzo stringa pubblica {get; dentro; }

}

Notare l'utilizzo della parola chiave data quando si dichiara il tipo di record. La parola chiave data, quando utilizzata nella dichiarazione di una classe, contrassegna il tipo come record. È possibile sfruttare un'istanza di tipo record per trasferire i dati attraverso i livelli garantendo allo stesso tempo l'immutabilità dei DTO.

Lo spazio dei nomi System.Collections.Immutable

Le raccolte immutabili sono quelle i cui membri non possono cambiare una volta che sono state create. Lo spazio dei nomi System.Collections.Immutable comprende diverse raccolte non modificabili. Questo spazio dei nomi contiene versioni non modificabili di elenchi, dizionari, array, hash, stack e code.

L'ImmutableStack può essere utilizzato per spingere e pop elementi più o meno allo stesso modo in cui facciamo con gli stack mutabili. Tuttavia, poiché ImmutableStack è una raccolta immutabile, i suoi elementi non possono essere modificati. Quindi, quando si effettua una chiamata al metodo pop per estrarre un elemento dallo stack, viene creato un nuovo stack e lo stack originale rimane inalterato.

Illustriamolo con un esempio. Il frammento di codice seguente mostra come è possibile inserire elementi in uno stack non modificabile.

var stack = ImmutableStack.Empty;

for (int i = 0; i <10; i ++)

{

    stack = stack.Push (i);

}

Il seguente programma dimostra che gli elementi di uno stack immutabile non possono essere modificati.

programma di classe

    {      

        static void Main (string [] args)

        {

            var stack = ImmutableStack.Empty;

            for (int i = 0; i <10; i ++)

            {

                stack = stack.Push (i);

            }

            Console.WriteLine ("Numero di elementi nello stack originale:

             "+ stack.Count ());

            var newStack = stack.Pop ();

            Console.WriteLine ("Numero di elementi nel nuovo stack:" +

            newStack.Count ());

            Console.ReadKey ();

        }

    }

Quando esegui il programma sopra, ecco come dovrebbe apparire l'output nella finestra della console.

Come puoi vedere nella Figura 1, lo stack originale immutabile (contenente 10 elementi) rimane invariato dopo una chiamata al metodo Pop (). Piuttosto, viene creato un nuovo stack immutabile con 9 elementi.

Le raccolte immutabili non offrono costruttori, ma puoi sfruttare il metodo factory statico chiamato Create, come mostrato nello snippet di codice riportato di seguito.

var list = ImmutableList.Create (1, 2, 3, 4, 5);

Se si desidera aggiungere o rimuovere un elemento da questa raccolta, verrà creato un nuovo elenco immutabile e l'elenco immutabile originale rimarrà invariato.

L'immutabilità è una scelta progettuale; significa che un'istanza di un tipo non può essere modificata dopo che è stata creata. Ad eccezione degli stack immutabili e delle code immutabili, tutte le raccolte immutabili si basano su alberi AVL. Quindi è possibile inserire elementi in qualsiasi posizione della raccolta, ovvero all'inizio, al centro o alla fine, senza la necessità di copiare l'albero nella sua interezza.

Come fare di più in C #:

  • Come usare le annotazioni dei dati in C #
  • Come lavorare con i GUID in C # 8
  • Quando usare una classe astratta e un'interfaccia in C #
  • Come lavorare con AutoMapper in C #
  • Come usare le espressioni lambda in C #
  • Come lavorare con i delegati Action, Func e Predicate in C #
  • Come lavorare con i delegati in C #
  • Come implementare un semplice logger in C #
  • Come lavorare con gli attributi in C #
  • Come lavorare con log4net in C #
  • Come implementare il modello di progettazione del repository in C #
  • Come lavorare con la riflessione in C #
  • Come lavorare con Filesystemwatcher in C #
  • Come eseguire l'inizializzazione pigra in C #
  • Come lavorare con MSMQ in C #
  • Come lavorare con i metodi di estensione in C #
  • Come utilizzare espressioni lambda in C #
  • Quando usare la parola chiave volatile in C #
  • Come utilizzare la parola chiave yield in C #
  • Come implementare il polimorfismo in C #
  • Come creare il proprio pianificatore di attività in C #
  • Come lavorare con RabbitMQ in C #
  • Come lavorare con una tupla in C #
  • Esplorazione di metodi virtuali e astratti in C #
  • Come utilizzare Dapper ORM in C #
  • Come utilizzare il modello di progettazione del peso mosca in C #