Si sa che i metodi corrispondenti agli event accessor devono seguire un pattern di denominazione (vedi CLS Rule 33 e ECMA-335, Partition I, 10.4). Per esempio, l'accessore add deve seguire il pattern:
void add_<EventName> (<DelegateType> handler)
Luca, in questo interessante post, è arrivato ad aver bisogno di richiamare questi event accessor. Provando col compilatore C#, si ottiene l'errore CS0571 ("cannot explicitly call operator or accessor"). Vediamo se, per il seguente snippet, il compilatore C# genera per i metodi add_FooFired e AddFooFired lo stesso codice IL:
class Foo
{
private FooFiredEvent mFooFired;
public event FooFiredEvent FooFired
{
add
{
mFooFired += value;
}
remove
{
mFooFired -= value;
}
}
public void AddFooFired(FooFiredEvent value)
{
mFooFired += new FooFiredEvent(value);
}
public void RemoveFooFired(FooFiredEvent value)
{
mFooFired -= new FooFiredEvent(value);
}
}
Questo è il codice per il corpo del metodo add_FooFired:
.maxstack 8
nop
ldarg.0
dup
ldfld class FooFiredEvent Foo::mFooFired
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass FooFiredEvent
stfld class FooFiredEvent Foo::mFooFired
ret
e questo per il corpo del metodo AddFooFired:
.maxstack 8
nop
ldarg.0
dup
ldfld class FooFiredEvent Foo::mFooFired
ldarg.1
ldftn instance void FooFiredEvent::Invoke()
newobj instance void FooFiredEvent::.ctor(object, native int)
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass FooFiredEvent
stfld class FooFiredEvent Foo::mFooFired
ret
Si nota il fatto che i due snippet IL non sono perfettamente identici (vedi le righe in rosso). Come fare allora per poter richiamare esplicitamente il metodo add_FooFired? Semplice: scriviamo la classe Foo in Visual J#! :-)
public class Foo
{
private FooFiredEvent mFooFired;
/** @event */
public void add_FooFired(FooFiredEvent value)
{
mFooFired = (FooFiredEvent)Delegate.Combine(mFooFired, value);
}
/** @event */
public void remove_FooFired(FooFiredEvent value)
{
mFooFired = (FooFiredEvent)Delegate.Remove(mFooFired, value);
}
public void AddFooFired(FooFiredEvent value)
{
add_FooFired(value);
}
public void RemoveFooFired(FooFiredEvent value)
{
remove_FooFired(value);
}
}
Rimanendo in J#, si può richiamare add_FooFired (e per questo abbiamo il metodo "wrapper" AddFooFired), a differenza di C#, dove si ottiene, come abbiamo visto, l'errore CS0571. Così, potete tranquillamente richiamare AddFooFired da qualsiasi linguaggio .NET.
Una domanda: in un commento al post precedente, un ragazzo rumeno mi chiedeva se avessi l'intenzione di scrivere i post in inglese. A voi darebbe fastidio? - l'idea è di non aprire un altro blog