Me lo sono chiesto più volte, ne avevo intuito il
potenziale ma non trovavo casi concreti di utilizzo, prima di oggi... Credo di
aver colto un aspetto fondamentale del metodo anonimo, cioè la differenza tra il
contesto di generazione del metodo e quello di esecuzione... Meglio
fare un esempio va
Supponiamo di avere queste due classi:
class Publisher
{
public event EventHandler<MyEventArgs> TestEvent;
public void Test()
{
if (TestEvent != null)
TestEvent(this, new MyEventArgs());
}
}
class Subscriber
{
public void Call(object sender, MyEventArgs e)
{
//do something
}
}
e supponiamo di voler sottoscrivere l'evento TestEvent di Publisher
col metodo Call di Subscriber, ma di volerlo fare alla "loosely coupled
event", ovvero senza sottoscriverlo direttamente ma con "qualcuno" in mezzo che
disaccoppi totalmente i due. Supponiamo che questo qualcuno consenta infine
di "pubblicare" eventi e di registrare "sottoscrittori". Potrebbe
assomigliare a questa classe:
class Attacher
{
public void Publish<TEventArgs>(object sender, string eventName, string publishName) where TEventArgs : EventArgs
{
Type t = sender.GetType();
EventInfo ei = t.GetEvent(eventName);
if (ei != null)
{
ei.AddEventHandler(sender,
Delegate.CreateDelegate(
typeof(EventHandler<TEventArgs>),
this,
"Handler",
false));
}
}
public void Subscribe(object target, string methodName, string publishName)
{
//add subscribers to 'attachments' structure,
skipped code...
}
}
attraverso publishName definisco un nome
pubblico per un evento, ed attraverso questo stesso nome sottoscrivo gli eventi.
Ora, tra le tante soluzioni possibili la prima che ho pensato era quella di
definire una funzione in Attacher che avesse la
firma corretta per poter sottoscrivere l'evento, e che si occupasse di
redirezionare gli eventi sui sottoscrittori. Ho quindi aggiunto a Attacher questo prototipo di metodo:
public void Handler(object sender, MyEventArgs e)
{
if (attachments.ContainsKey("eventname"))
{
IList<Attachment> list = attachments["eventname"];
foreach (Attachment a in list)
a.Invoke(new object[] { sender, e });
}
}
ma ecco qui 2 problemi: il primo sul tipo "cablato" MyEventArgs dell'argomento dell'evento, ma non è
l'oggetto del post e quindi vado avanti , il secondo è come recuperare da una non
meglio precisata struttura dati (attachments) i
sottoscrittori dato il nome dell'evento, rappresentato dalla stringa "eventname" che evidentemente deve corrispondere al
publishName passato al metodo Publish. Ma Handler è
un altro metodo, e non sa niente di publishName...
Ecco qui che arriva il "metodo anonimo": se sostituisco la chiamata AddEventHandler in Publish vista sopra con la seguente:
ei.AddEventHandler(sender,
(EventHandler<TEventArgs>)delegate(object s, TEventArgs ea)
{
if (attachments.ContainsKey(
publishName
))
{
IList<Attachment> list = attachments[
publishName
];
foreach(Attachment a in list)
a.Invoke(new object[] {s, ea});
}
});
che riprende il codice del metodo Handler ma
esplicita il parametro publishName, ecco che il
nostro metodo viene "generato al volo", e la chiave con cui cerco i subscribers
durante l'esecuzione dell'handler ora è proprio la publishName passata come parametro al metodo Publish, ma il suo valore NON dipende dal momento in
cui il codice dell'handler verrà chiamato (in quel momento publishName non esiste), ma dal momento in cui il
codice verrà generato, cioè quando chiamo Publish.
Insomma, non so se mi sono spiegato, ma è geniale, io già mi vedevo
impelagato dietro ad astruse strutture dati ed invece con 3 linee di codice ho
una soluzione pulitissima e (credo) efficiente. Insomma, gli "anonymous
methods" a qualcosa servono...
powered by IMHO 1.3
posted @ mercoledì 21 giugno 2006 02:59