Howto invoke an event via reflection
Posté le mar. 04 avril 2017 dans blog
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)
String
is the name of the field to get and
BindingFlags
a bitmask of serarching flags. Note: To use reflexion, use
"System.Reflection" Let's try a GetField
:
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) let's try:
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
?
var my_event_invoke = my_event_type.GetMethod("Invoke");
Searching how to call the Invoke... by reflection? Invoking invoke?
Let's try:
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:
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 });
}
}
}