views:

63

answers:

1

Is it possible to use Reflection is C# to fire an event? Say I have a situation like this:

public delegate void SomeEventHandler(object sender, BenArgs e);

class EventHub
{
    public event SomeEventHandler SOME_EVENT;

    public void fireEvent(String eventName)
    {
        SomeEventHandler evt = (SomeEventHandler) Delegate.CreateDelegate(typeof(SomeEventHandler), this, eventName);

        evt.Invoke(null, null);
    }
}

Meaning if I call

EventHub.fireEvent("SOME_EVENT")

then it makes the event hub fire SOME_EVENT? I've tried this and am just getting exceptions.

This is mostly a curiosity of mine, I know that in this case I could just as easily fire the event without reflection.

+2  A: 

Assuming your current scenario, i.e.:

  1. A field-like event.
  2. The backing delegate-field has the same name as the event.
  3. (this, EventArgs.Empty) are valid arguments to pass to the delegate.

You can do something like this (more argument validation required):

public void fireEvent(String eventName)
{
    // Get a reference to the backing field
    var del = (Delegate)typeof(EventHub)
                .GetField(eventName, BindingFlags.NonPublic | BindingFlags.Instance)
                .GetValue(this);

     // Invoke the delegate, it's invocation-list will contain the listeners
     if(del != null)
        del.DynamicInvoke(this, EventArgs.Empty);
}

Usage:

  var eHub = new EventHub();
  eHub.SOME_EVENT += delegate { Console.WriteLine("SOME_EVENT fired.."); };      
  eHub.fireEvent("SOME_EVENT");

Now, you can generalize this idea with an extension method on object if you like, but all of this is a really bad idea. This problem can't be solved in the general case because one can't know how an event is "implemented." There could be arbitrary code inside the add and remove methods, and the logic to "fire" the event could also be just about anything. There might not even be a backing multicast delgate field to store the listeners.

In any case, trying to tell an object to fire an event is almost always a sign of a major design-flaw, IMO. If you still really do want this, it would be much better to declare a method like this in your class:

public void RaiseXXXEvent() { ... } 
Ani
Ha! It works! Thanks very much. Any reason I would want to use Dynamic invoke over just Invoke?
Ben
@Ben: Cheers. `System.Delegate` doesn't declare an `Invoke` method.
Ani
Amazing! Just now I tried with `BindingFlags.Instance` only because I think the event is `public`. But I get `FieldInfo[0]`. Why?
Danny Chen
@Danny Chen: The event is public, but the backing delegate field is private.
Ani
@Ani: Why there is a "backing delegate field"? Can you provide a link to explain this? Thanks very much.
Danny Chen
@Danny Chen: I think the best reference would be "Section 10.8.1 Field-like events" of the C# language specification 4.0.
Ani
@Ani: Thanks very much.
Danny Chen