Menu
Coddy logo textTech

Modelli di immutabilità

Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 34 di 70.

L’immutabilità porta l’incapsulamento alle sue estreme conseguenze logiche: una volta creato, un oggetto non può mai cambiare. Questo elimina intere categorie di bug, perché non devi mai preoccuparti che qualcosa modifichi inaspettatamente i tuoi dati.

Il modo più semplice per creare una classe immutabile è usare campi readonly con un costruttore che imposta tutti i valori e non fornire setter:

public class Point
{
    public readonly int X;
    public readonly int Y;
    
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

Una volta creato un Point, le sue coordinate non possono cambiare. Ma cosa succede se ti serve una versione modificata? Invece di modificare l'oggetto esistente, ne restituisci uno nuovo:

public Point Move(int deltaX, int deltaY)
{
    return new Point(X + deltaX, Y + deltaY);
}

Il punto originale rimane invariato mentre ne ottieni uno nuovo con valori aggiornati. Questo schema viene utilizzato in tutto .NET: le stringhe, ad esempio, sono immutabili. Quando chiami ToUpper(), ottieni una nuova stringa anziché modificare quella originale.

Gli oggetti immutabili sono intrinsecamente sicuri per l'uso con più thread, poiché nessun codice può modificarli dopo la loro creazione. Sono anche più facili da comprendere, perché sai che il loro stato non cambierà mai in modo imprevisto.

challenge icon

Sfida

Facile

Costruiamo un sistema monetario immutabile che mostri come si possono progettare oggetti che non cambiano mai dopo la creazione. Creerai una classe Money in cui ogni operazione restituisce un nuovo oggetto invece di modificare quello originale: un modello che rende il tuo codice più sicuro e più facile da comprendere.

Organizzerai il codice in due file:

  • Money.cs: crea una classe Money immutabile nello spazio dei nomi Finance. Il tuo denaro deve avere:
    • Due campi readonly: Amount (decimal) e Currency (string)
    • Un costruttore che imposta entrambi i valori: una volta creato, un oggetto Money non può mai cambiare
    • Un metodo Add(decimal value) che restituisce un nuovo oggetto Money con l'importo aumentato (stessa valuta)
    • Un metodo Subtract(decimal value) che restituisce un nuovo oggetto Money con l'importo diminuito (stessa valuta)
    • Un metodo Convert(string newCurrency, decimal rate) che restituisce un nuovo oggetto Money con l'importo moltiplicato per il tasso e la nuova valuta
    • Un metodo GetDisplay() che restituisce una stringa nel formato "{Amount} {Currency}"
    Ricorda: nessuno di questi metodi deve modificare l'oggetto originale: restituiscono tutti istanze di Money completamente nuove!
  • Program.cs: nel file principale, mostra l'immutabilità in azione. Crea un oggetto Money iniziale, poi esegui delle operazioni mantenendo i riferimenti sia all'originale sia ai risultati. In questo modo dimostrerai che l'originale non cambia mai, nemmeno dopo più operazioni.

Riceverai quattro valori in ingresso:

  • Importo iniziale (decimal)
  • Valuta iniziale (string)
  • Importo da aggiungere (decimal)
  • Tasso di conversione in EUR (decimal)

Stampa l'output in questo formato:

Original: {GetDisplay()}
After add: {GetDisplay()}
Original unchanged: {GetDisplay()}
Converted: {GetDisplay()}

Ad esempio, se i valori in ingresso sono 100.00, USD, 50.00 e 0.85, l'output dovrebbe essere:

Original: 100.00 USD
After add: 150.00 USD
Original unchanged: 100.00 USD
Converted: 127.50 EUR

Nota che l'oggetto Money originale mostra ancora 100.00 USD anche dopo aver chiamato Add(): questa è l'immutabilità! Il metodo Add() ha creato un oggetto completamente nuovo con 150.00 USD, lasciando intatto l'originale. La conversione viene eseguita sul risultato dell'operazione di addizione.

Provalo tu

using System;
using Finance;

class Program
{
    public static void Main(string[] args)
    {
        // Leggi i dati di input
        decimal initialAmount = Convert.ToDecimal(Console.ReadLine());
        string initialCurrency = Console.ReadLine();
        decimal amountToAdd = Convert.ToDecimal(Console.ReadLine());
        decimal conversionRate = Convert.ToDecimal(Console.ReadLine());

        // TODO: Crea un oggetto Money iniziale con l'importo e la valuta iniziali

        // TODO: Stampa l'importo originale usando GetDisplay()

        // TODO: Chiama Add() sull'oggetto originale e memorizza il risultato in una nuova variabile

        // TODO: Stampa il risultato dopo l'aggiunta usando GetDisplay()

        // TODO: Stampa di nuovo l'oggetto originale per dimostrare che non è cambiato

        // TODO: Converti il risultato dell'aggiunta in EUR usando il tasso di conversione

        // TODO: Stampa l'importo convertito usando GetDisplay()
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C# online