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 });
        }
    }
}