Menu
Coddy logo textTech

Nozioni di base sull'iniezione delle dipendenze

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

Dependency Injection (DI) è una tecnica in cui una classe riceve le sue dipendenze dall'esterno invece di crearle autonomamente. Questo rende il codice più flessibile, testabile e debolmente accoppiato.

Senza DI, una classe crea le proprie dipendenze, rendendo difficile modificarle o testarle:

public class OrderService
{
    private EmailSender sender = new EmailSender();  // Strettamente accoppiato
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Con la DI, le dipendenze vengono passate tramite il costruttore:

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

Ora OrderService non sa né gli interessa se sta usando email, SMS o un mittente simulato per i test. La dipendenza viene «iniettata» quando l'oggetto viene creato:

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // Email: Ordine effettuato

Questo schema segue il principio di dipendere dalle astrazioni (interfacce) anziché dalle implementazioni concrete. Permette di sostituire le implementazioni senza modificare la classe che le utilizza, un aspetto essenziale per i test unitari e per mantenere architetture flessibili.

challenge icon

Sfida

Facile

Creiamo un sistema di registrazione che dimostri la potenza dell’iniezione delle dipendenze. Invece di codificare rigidamente il modo in cui vengono scritti i log, creerai una classe flessibile Logger che può funzionare con qualsiasi destinazione di registrazione: console, simulazione di un file o qualsiasi altra cosa, senza conoscerne i dettagli.

Organizzerai il codice in tre file:

  • ILogWriter.cs: Definisci un’interfaccia chiamata ILogWriter nello spazio dei nomi Logging. Questa interfaccia rappresenta il contratto per qualsiasi destinazione di registrazione e dovrebbe avere un solo metodo Write(string message) che restituisce una stringa che descrive dove è stato scritto il messaggio.
  • LogWriters.cs: Crea due implementazioni concrete di ILogWriter nello spazio dei nomi Logging:
    • ConsoleLogWriter - il suo metodo Write restituisce Console: {message}
    • FileLogWriter - riceve un nome file tramite il costruttore e il suo metodo Write restituisce File[{filename}]: {message}
  • Logger.cs: Crea una classe Logger nello spazio dei nomi Logging che riceve la propria dipendenza tramite l’iniezione nel costruttore. La classe Logger dovrebbe:
    • Accettare un ILogWriter tramite il costruttore e memorizzarlo in un campo privato
    • Avere un metodo Log(string message) che delega la chiamata al writer iniettato e restituisce il risultato
  • Program.cs: Dimostra l’iniezione delle dipendenze creando due logger diversi: uno con ConsoleLogWriter e uno con FileLogWriter. Mostra come la stessa classe Logger si comporta in modo diverso a seconda della dipendenza iniettata.

Riceverai due input:

  • Il nome del file per il logger su file
  • Il messaggio da registrare

Crea un Logger con ConsoleLogWriter e registra il messaggio. Poi crea un altro Logger con FileLogWriter (usando il nome del file fornito in input) e registra lo stesso messaggio. Stampa ogni risultato su una riga separata.

Per esempio, se gli input sono app.log e System started, l’output dovrebbe essere:

Console: System started
File[app.log]: System started

Nota che la classe Logger non cambia mai: funziona con qualsiasi implementazione di ILogWriter. Questa è l’essenza dell’iniezione delle dipendenze: la classe Logger dipende da un’astrazione (l’interfaccia) e l’implementazione concreta viene «iniettata» dall’esterno. In seguito potresti aggiungere facilmente un DatabaseLogWriter o un CloudLogWriter senza modificare affatto la classe Logger!

Provalo tu

using System;
using Logging;

class Program
{
    public static void Main(string[] args)
    {
        // Leggi i dati di input
        string filename = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: Crea un Logger con un ConsoleLogWriter e registra il messaggio
        // Stampa il risultato

        // TODO: Crea un altro Logger con un FileLogWriter (usando filename) e registra lo stesso messaggio
        // Stampa il risultato
    }
}
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