I DELEGATE
I 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
{
public delegate int MyDelegate(int a, int b);
}
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)
{
Console.WriteLine(“Method1: ” + message);
}
public void Method2(string message)
{
Console.WriteLine(“Method2: ” + 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!
Lascia un commento