I DELEGATE

C sharpI delegate in C Sharp sono un nuovo tipo dopo le classi le struct e le interface. È un tipo reference le cui istanze ci permettono di trattare i metodi come se fossero oggetti. Un delegate è privo di implementazione, può essere definito a livello di namespace ma anche di classe. Vediamo come si dichiara un delegate.

namespace Delegate

Come vedi un delegate si dichiara con la parola chiave delegate, per il resto somiglia alla definizione di un metodo, abbiamo dichiarato un tipo di ritorno int e due parametri di tipo intero a e b. È un po' come un metodo dichiarato all'interno di una interface, la particolarità è che nella dichiarazione c'è la keyword delegate. Questo particolare delegate rappresenta qualsiasi metodo che prenda in input due interi e restituisca un int.

 

UTILIZZO DEI DELEGATE

using System;
namespace Delegate
{
    public delegate int MyDelegate(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate md = Somma;//PRIMA FORMA DI INIZIALIZZAZIONE DEL DELEGATE
            //MyDelegate md1 = new MyDelegate(Somma);SECONDA FORMA PER INIZIALIZZARE UN DELEGATE. MENO COMUNE.
            int result = md(10,5);
            Console.WriteLine($"Somma: {result}");
            md=Differenza;
            result = md(10,5);
            Console.WriteLine($"Differenza: {result}");
            md=Moltiplicazione;
            result = md.Invoke(10,5);//SI PUO' USARE ANCHE IL METODO Invoke PER CHIAMARE IL METODO.
            Console.WriteLine($"Moltiplicazione: {result}");
            
            static int Somma(int arg1, int arg2)
            {
                return arg1+arg2;
            }
            static int Differenza(int arg1, int arg2)
            {
                return arg1 - arg2;
            }
            static int Moltiplicazione(int arg1, int arg2)
            {
                return arg1 * arg2;
            }
        }
    }
}

Come vedi dal codice sopra riportato ho dichiarato tre metodi Somma, Differenza e Moltiplicazione ognuno avente la stessa signature del delegate. Con l’istruzione

MyDelegate md = Somma;

Ho inizializzato la variabile istanza del delegate con il metodo Somma, l’invocazione di tale metodo avviene con l’istruzione:

int result = md(10,5); o con l’istruzione

int result = md.Invoke(10,5);

Una volta effettuata la somma la stessa istanza del delegate può puntare un nuovo metodo. Ho utilizzato la parola puntare perché chi ha familiarità con il linguaggio C o C++ può osservare che un delegate è simile ad un puntatore a funzione, il problema dei puntatori è che spesso sono causa di bug difficili da scovare. Il C# invece ci mette a disposizione un meccanismo più trasparente e sicuramente meno incline a bug.

I DELEGATE IN C SHARP I DELEGATE MULTICAST

Vediamo di chiarire alcuni aspetti prima di introdurre il codice per un multicast delegate. Tale tipo di delegate o meglio la variabile istanza del delegate viene inizializzata come già visto. Con l’operatore += si assegnano all’istanza creata a più metodi, al momento dell’invocazione i metodi verranno eseguiti in cascata. Vediamo due implicazioni da conoscere:

  • Se il delegate restituisce un valore allora al momento dell’invocazione del multicast delegate verrà ritornato solo il valore dell’ultimo metodo eseguito. Quindi i delegate multicast vanno usati salvo rare eccezioni con il tipo restituito void.
  • Se viene generata un’eccezione in uno dei metodi la catena di invocazione si interrompe.
using System;
namespace Delegate
{
    public delegate void MyDelegate(int a, int b);
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate md = Somma;
            md += Differenza;
            md+=Moltiplicazione;
            md.Invoke(10,5);//SI PUO' USARE ANCHE IL METODO Invoke PER CHIAMARE IL METODO.
            
            static void Somma(int arg1, int arg2)
            {
                 Console.WriteLine($"Somma: {arg1 + arg2}");
            }
            static void Differenza(int arg1, int arg2)
            {
                Console.WriteLine($"Differenza: {arg1 - arg2}");
            }
            static void Moltiplicazione(int arg1, int arg2)
            {
               Console.WriteLine($"Moltiplicazione: {arg1 * arg2}");
            }
        }
    }
}

I DELEGATE IN C SHARP I DELEGATE GENERICI

using System;
namespace Delegate
{
    public delegate void MyDelegate<T>(T a, T b) where T:struct;
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate<int> md1 = Somma;
            MyDelegate<double> md2 = Differenza;
            MyDelegate<float> md3 = Moltiplicazione;
            md1.Invoke(12,7);
            md2.Invoke(100.45,90.78);
            md3.Invoke(12.8f, 13.4f);            
            static void Somma(int arg1, int arg2)
            {
                 Console.WriteLine($"Somma: {arg1 + arg2}");
            }
            static void Differenza(double arg1, double arg2)
            {
                Console.WriteLine($"Differenza: {arg1 - arg2}");
            }
            static void Moltiplicazione(float arg1, float arg2)
            {
               Console.WriteLine($"Moltiplicazione: {arg1 * arg2}");
            }
        }
    }
}

DELEGATE PREDEFINITI ACTION E FUNC

Il .NET Framework ci mette a disposizione due delegate predefiniti Action e Func. La differenza tra i due sta nel fatto che Action non restituisce valori, quindi il valore restituito è void e può accettare fino a 16 parametri di tipo. Il delegate Func viceversa lo usiamo quando abbiamo bisogno di un valore di ritorno. Vediamo come si presentano questi due delegate predefiniti.

public delegate void Action();

public delegate void Action(T arg);

public delegate void Action<T1,T2>(T1 arg1, T2 arg2);

public delegate TResult Func();

public delegate TResult Func<T1, TResult>(T1 arg);

public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);

using System;
namespace Delegate
{
    class Program
    {
        static void Main(string[] args)
        {
            Action<int,double> myAction = Somma;
            myAction+=Differenza;
            myAction+=Moltiplicazione;
            myAction.Invoke(10,89.98);            
            static void Somma(int arg1, double arg2)
            {
                 Console.WriteLine($"Somma: {arg1 + arg2}");
            }
            static void Differenza(int arg1, double arg2)
            {
                Console.WriteLine($"Differenza: {arg1 - arg2}");
            }
            static void Moltiplicazione(int arg1, double arg2)
            {
               Console.WriteLine($"Moltiplicazione: {arg1 * arg2}");
            }
            Func<double,double> MyFunc = RadiceQuadrata;
            double result = MyFunc.Invoke(144);
            Console.WriteLine(result);
            static double RadiceQuadrata(double arg1)
            {
                return Math.Sqrt(arg1);
            }
        }
    }
}

APPROFONDIMENTO SUI DELEGATE

In C#, un delegato è un tipo che rappresenta riferimenti a metodi con una particolare firma e tipo di ritorno. È simile a un puntatore a funzione in C++, ma è sicuro dal punto di vista del tipo e dell'ambiente. I delegati sono utilizzati per passare metodi come parametri a un'altra funzione. Questa funzionalità è particolarmente utile per la programmazione orientata agli eventi e per implementare callback.

Ecco una descrizione più dettagliata e un esempio di utilizzo dei delegati in C#:

Caratteristiche principali dei delegati:

1. Firma del Metodo: Un delegato può fare riferimento solo a metodi che abbiano una firma corrispondente (ossia, stesso tipo di ritorno e stessi parametri).

2. Multicast: I delegati possono essere concatenati insieme; cioè, possono fare riferimento a più metodi contemporaneamente. Quando viene invocato un delegato multicast, tutti i metodi ad esso associati vengono chiamati in sequenza.

3. Tipizzazione Sicura: I delegati sono sicuri dal punto di vista del tipo, il che significa che il compilatore controlla i tipi dei metodi assegnati ai delegati, prevenendo errori di tipo.

Definizione e Utilizzo di un Delegato:

Definizione di un Delegato

// Definizione di un delegato
public delegate void MyDelegate(string message);

Dichiarazione di Metodi Compatibili con il Delegato

// Metodo compatibile con il delegato
public void Method1(string message)

public void Method2(string message)

Assegnazione di Metodi al Delegato

// Creazione di un'istanza del delegato e assegnazione dei metodi
MyDelegate del = new MyDelegate(Method1);
del += Method2; // Aggiunta di un altro metodo al delegato (multicast)

// Invocazione del delegato
del("Hello, World!");

// Output:
// Method1: Hello, World!
// Method2: Hello, World!

LINK AI PRECEDENTI POST

LINK AL CODICE SU GITHUB

YouTube video player 4
YouTube video player 5
YouTube video player 6