102 lines
3.9 KiB
Markdown
102 lines
3.9 KiB
Markdown
Title: Howto invoke an event via reflection
|
|
|
|
|
|
Why this article ? Because of this note found on the MSDN's `EventInfo`
|
|
page:
|
|
|
|
> EventInfo is not intended to be used to raise events. An object
|
|
> raises events as dictated by its internal state.
|
|
|
|
Let's try to raise an event with reflection ... Firstly, let's search,
|
|
but not in `GetEvent`, in `GetField` : [Type.GetField(String,
|
|
BindingFlags)](http://msdn.microsoft.com/en-us/library/4ek9c21e.aspx)
|
|
`String` is the name of the field to get and
|
|
[BindingFlags](http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx)
|
|
a bitmask of serarching flags. Note: To use reflexion, use
|
|
"System.Reflection" Let's try a `GetField`:
|
|
|
|
:::csharp
|
|
FieldInfo my_event_FieldInfo = this.GetType().GetField("my_event",
|
|
BindingFlags.NonPublic
|
|
| BindingFlags.Instance);
|
|
|
|
Yeah! It's not `null`! we have now the `FieldInfo` of our event. What to
|
|
do now ? in a `FieldInfo`, we do not have something like "Fire the event",
|
|
huh But what about "GetValue" ? The "Value" of a "FieldInfo" is the
|
|
field, so the Value of an event's `FieldInfo` isn't the Event?
|
|
[FieldInfo.GetValue(object)](http://msdn.microsoft.com/en-us/library/system.reflection.fieldinfo.getvalue.aspx) let's try:
|
|
|
|
:::csharp
|
|
object my_event_by_reflection = my_event_FieldInfo.GetValue(this);
|
|
|
|
Is `null` ... ): Ohhhh but, while not registered, an event is `null`... so,
|
|
let's try adding a handler... Is not null!! Yeah, so we have our event
|
|
by reflection now.
|
|
|
|
Note for those who just said "Why giving an object to `GetValue`? And
|
|
why giving 'this'":
|
|
|
|
- Take a look at the first "this.getType()"
|
|
- Deduce that it ask the Object to give you its Type, an Object knows
|
|
its Type.
|
|
- Note that a Type can't know its Objects...
|
|
- Finally to get a Field of your Object, you ask the Type to give it
|
|
or your Object, giving a reference to your Object, here : 'this';
|
|
|
|
|
|
Now, we have an object, which is the event to call, but, how to call
|
|
it? By reflection? but... where to search? TRICK: Put a
|
|
breakpoint just after the `GetValue`, when breaked, add a watch on
|
|
`my_event_by_reflection.GetType()` and browse it... try
|
|
`my_event_by_reflection.GetType().GetFields()`... nothing... try
|
|
`my_event_by_reflection.GetType().GetMethods()`... browse it... OH
|
|
? What is `Invoke` ?
|
|
|
|
:::csharp
|
|
var my_event_invoke = my_event_type.GetMethod("Invoke");
|
|
|
|
Searching how to call the Invoke... by reflection? Invoking invoke?
|
|
|
|
Let's try:
|
|
|
|
:::csharp
|
|
my_event_invoke.Invoke(my_event_by_reflection, new object[] {this, new EventArgs()} );
|
|
|
|
Invoke take the instance of this type, so the object where GetType where
|
|
called, and in second parameter an array of object to be given as
|
|
parameter to the method called, we have to give an object and an
|
|
eventArgs. It Works ! here the full working source code:
|
|
|
|
:::csharp
|
|
using System.Reflection;
|
|
|
|
class Cage_en_metal
|
|
{
|
|
public event EventHandler ecraser;
|
|
|
|
public Cage_en_metal()
|
|
{
|
|
ecraser += new EventHandler(Libellule_ecraser);
|
|
fireEvent("ecraser", new EventArgs());
|
|
}
|
|
|
|
void Libellule_ecraser(object sender, EventArgs e)
|
|
{
|
|
Console.WriteLine("Splatch !");
|
|
}
|
|
|
|
void fireEvent(string handler, EventArgs eventArgs)
|
|
{
|
|
var eventInfo = this.GetType().GetField(handler,
|
|
BindingFlags.Instance
|
|
| BindingFlags.NonPublic);
|
|
if (eventInfo != null)
|
|
{
|
|
var event_member = eventInfo.GetValue(this);
|
|
// Note : If event_member is null, nobody registered to the event, you can't call it.
|
|
if (event_member != null)
|
|
event_member.GetType().GetMethod("Invoke").Invoke(event_member, new object[] { this, eventArgs });
|
|
}
|
|
}
|
|
}
|