Classe Delegate:
Rappresenta un delegato, ossia la struttura di dati
che fa riferimento a un metodo static o a un'istanza
di classe e un metodo di istanza di quella classe.
Codice thread safe:
I membri statici pubblici (Shared in Visual Basic)
di questo tipo sono validi per le operazioni multithreading.
I membri di istanza non sono garantiti come thread safe.
Osservazioni:
La classe Delegate è la classe base per i tipi delegati.
Tuttavia, soltanto il sistema e i compilatori possono derivare
in modo esplicito dalla classe Delegate o dalla classe
MulticastDelegate. Non è inoltre consentita la derivazione di un
nuovo tipo da un tipo delegato. La classe Delegate non è considerata
un tipo delegato, in quanto classe utilizzata per derivare i tipi
delegati.
Nella maggior parte dei linguaggi viene implementata una parola
chiave delegate e i compilatori per tali linguaggi sono in grado di
derivare dalla classe MulticastDelegate. Gli utenti devono quindi
utilizzare la parola chiave delegate fornita con il linguaggio.
Con la dichiarazione di un tipo delegato viene stabilito un contratto
nel quale è specificata la firma di uno o più metodi. Un delegato è
un'istanza di un tipo delegato e fa riferimento a uno o più dei
seguenti oggetti:
Un oggetto di destinazione che non è riferimento Null (Nothing in
Visual Basic) e un metodo di istanza dell'oggetto di destinazione
Un metodo static. Un delegato può fare riferimento a un metodo solo
qualora la firma del metodo corrisponda esattamente alla firma
specificata dal tipo delegato. Quando un delegato fa riferimento a un metodo di istanza, viene archiviato un riferimento al punto di
ingresso del metodo e un riferimento a un oggetto, chiamato destinazione, che rappresenta l'istanza di classe sulla quale viene
richiamato il metodo. La destinazione di un metodo di istanza non può
essere riferimento Null (Nothing). Quando un delegato fa riferimento
a un metodo static, viene archiviato un riferimento al punto di
ingresso del metodo. La destinazione di un metodo static è
riferimento Null (Nothing).
L'elenco chiamate di un delegato è un gruppo ordinato di delegati in
cui ciascun elemento dell'elenco richiama esattamente uno dei metodi
richiamati dal delegato. In un elenco chiamate possono essere
presenti metodi duplicati. Durante una chiamata, i metodi vengono
richiamati dal delegato nell'ordine in cui si trovano nell'elenco
chiamate. Un delegato tenta di richiamare tutti i metodi presenti
nell'elenco chiamate, i duplicati vengono richiamati una volta per
ogni istanza trovata nell'elenco chiamate. I delegati non sono
modificabili. Una volta creato, l'elenco chiamate di un delegato
rimarrà immutato.
Un delegato può essere di tipo multicast (combinabile) o singlecast
(non combinabile). Mediante i delegati multicast o combinabili
vengono richiamati uno o più metodi. È inoltre possibile utilizzare
delegati multicast in operazioni combinate. Mediante i delegati
singlecast o non combinabili viene richiamato esattamente un metodo.
Non è possibile utilizzare un delegato singlecast in operazioni
combinate. Nell'elenco chiamate di un delegato singlecast A è
contenuto un solo elemento: un riferimento a A.
I delegati esistenti non verranno modificati da operazioni combinate,
quali Combine e Remove. Mediante tale operazione verrà invece
restituito un nuovo delegato contenente i risultati dell'operazione,
un delegato invariato o riferimento Null (Nothing). Mediante
un'operazione combinata viene restituito riferimento Null (Nothing)
quando il risultato dell'operazione è un delegato che non fa
riferimento ad almeno un metodo. Quando l'operazione richiesta non ha
effetto, viene restituito un delegato invariato.
Qualora un metodo richiamato generi un'eccezione, l'esecuzione del
metodo viene interrotta, l'eccezione passata di nuovo al chiamante
del delegato e i metodi restanti nell'elenco chiamate non verranno
richiamati. L'intercettazione di un'eccezione nel chiamante non
odifica questo comportamento.
Quando nella firma dei metodi richiamati da un delegato è contenuto
un valore restituito, il delegato restituisce il valore restituito
dell'ultimo elemento nell'elenco chiamate. Quando la firma contiene
un parametro passato dal riferimento, il valore finale del parametro
è il risultato dell'esecuzione in sequenza di tutti i metodi presenti
nell'elenco e dell'aggiornamento del valore del parametro.
I compilatori forniscono al delegato due metodi aggiuntivi:
BeginInvoke e EndInvoke. Per ulteriori informazioni su questi metodi,
vedere Cenni preliminari sulla programmazione asincrona.
L'equivalente più vicino a un delegato in C o C++ è un puntatore a
funzione. Tuttavia, un puntatore a funzione è in grado di fare
riferimento soltanto a funzioni static, mentre un delegato è in grado
di fare riferimento sia a metodi static sia a metodi di istanza.
Quando il delegato fa riferimento a un metodo di istanza, viene
archiviato non solo il riferimento al punto di ingresso del metodo,
ma anche un riferimento all'istanza di classe per la quale richiamare
il metodo. A differenza dei puntatori a funzione, i delegati sono
orientati ad oggetti, protetti e indipendenti dai tipi.
Esempio:
Nell'esempio riportato di seguito viene illustrata la modalità di definizione di un delegato standard.
codice:
using System;
public class SamplesDelegate {
// Declares a delegate for a method that takes in an int and returns a String.
public delegate String myMethodDelegate( int myInt );
// Defines some methods to which the delegate can point.
public class mySubClass {
public static String myStringMethod ( int myInt ) {
if ( myInt > 0 )
return( "positive" );
if ( myInt < 0 )
return( "negative" );
return ( "zero" );
}
public static String mySignMethod ( int myInt ) {
if ( myInt > 0 )
return( "+" );
if ( myInt < 0 )
return( "-" );
return ( "" );
}
}
public static void Main() {
// Creates one delegate for each method.
myMethodDelegate myD1 = new myMethodDelegate( mySubClass.myStringMethod );
myMethodDelegate myD2 = new myMethodDelegate( mySubClass.mySignMethod );
// Invokes the delegates.
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".\n", 5, myD1( 5 ), myD2( 5 ) );
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".\n", -3, myD1( -3 ), myD2( -3 ) );
Console.WriteLine( "{0} is {1}; use the sign \"{2}\".\n", 0, myD1( 0 ), myD2( 0 ) );
}
}
/*
Output:
5 is positive; use the sign "+".
-3 is negative; use the sign "-".
0 is zero; use the sign "".
*/