none
raising an event via reflection

    Question

  • Using reflection is it possible to check if an event has a handler and more importantly raise that event. I have a string with a value of the event and the object instance  which I need to fire.
    Friday, September 29, 2006 6:59 PM

Answers

  • Thanks for the VB example. Seems a lot of folks are stuck on this issue.

    Here is a c# flavor of it.

          public event EventHandler<EventArgs> MyEventToBeFired;

            public void FireEvent(Guid instanceId, string handler)
            {

                // Note: this is being fired from a method with in the same class that defined the event (i.e. "this").


                EventArgs e = new EventArgs(instanceId); 

                MulticastDelegate eventDelagate =
                      (MulticastDelegate)this.GetType().GetField(handler,
                       System.Reflection.BindingFlags.Instance |
                       System.Reflection.BindingFlags.NonPublic).GetValue(this); 

                Delegate[] delegates = eventDelagate.GetInvocationList();

                foreach (Delegate dlg in delegates)
                {
                    dlg.Method.Invoke(dlg.Target, new object[] { this, e }); 
                }
            }

            FireEvent(new Guid(),  "MyEventToBeFired");

    Wednesday, November 22, 2006 4:34 PM

All replies

  • Why dont you Check it. I think it'll hardly take 5 minutes if your assemblies are already ready.

    Best of Luck!!!

    Friday, September 29, 2006 9:19 PM
  • I did. EventInfo does not have a invoke or raise method. it does have a GetRaiseMethod (some conflicting info on what it was meant to do) that returns null if the event was declared in c# or vb.net  per microsoft documentation

    "This method returns a null reference (Nothing in Visual Basic) for events declared with the C# event keyword or the Visual Basic Event keyword. This is because the C# and Visual Basic compilers do not generate such a method."

     

    I'm not seeing the ability in eventinfo. was this left out due to security issues. Should I try to use another type to do this?

    Friday, September 29, 2006 10:21 PM
  • Have you tried this in your called assembly when you are rasing event;

    if(SomeEvent != null)

    {

           SomeEvent(this, EventArgs.Empty);

    }

    And yes Sorry I listened for the first time that there is an EventInfo class, I'll have a look on this. Man is always learning :$.

    Try this and tell me what happens.

    Best Regards,

    Saturday, September 30, 2006 8:19 AM
  • I'll elaborate on my project. I have a windows workflow that a windows application is able to query all the available events. From this I have a string[] of event names. I've displayed this in a listbox. the user selects the event they wish to fire/confirm action. I have an instance of a type and a string name of the event. I've googled this for a while and the only reference to it I found concluded that this may not be possible. Seems hard to believe. What I need is something like the following

    class LocalService

    {

    public event MortgageEventHandler ApplicationApproved;

    }

    ...

    //in windows app

    private void fireevent(string eventName)

    {

    ??????(localServiceInstance,eventName); //how to fire ApplicationApproved with no reference but  a string variable eventName="ApplicationApproved" .  EventInfo doesn't seem to have a method to call ApplicationApproved.

     

    }

     

    Saturday, September 30, 2006 6:50 PM
  • I also think its not possible, Atleast not in my knowledge that you fire an event like your are tryint to do.

    The other way it could be like this:

    string[] evens = new strin[] {"Accepted", "Rejected", "Delayed"}

    private void FireEvent(string eventName)

    {

    switch(eventName)

    {

    case "Accepted":

               if(Accepted != null)

                        Accepted(new object(), EventArgs.Empty);

              break;

    case "Rejected":

              if(Rejected != null)

                        Rejected(new object(), EventArgs.Empty);

              break;

    default:

              if(Delayed != null)

                        Delayed(new object(), EventArgs.Empty);

              break;

    }

    }

    Does it make a sense to you or help?

    Best Regards,

    Saturday, September 30, 2006 6:59 PM
  • You can do this via reflection.  Every event you define also generates a field which has your event's name plust Event appended to the end.  So if you have an event called MyEvent, there will be a field on that object called MyEventEvent.  You can get this via reflection, and dig down into it to invoke it.  Here's some sample code.  If you have any other questions, you can email me at christophilus at our good friends over at hotmail.

    Public Sub Raise(ByVal objWithEvent As Object, ByVal eventName As String, ByVal params() As Object)

    Dim Typ As Type = objWithEvent.GetType()

    Dim Evt As Reflection.FieldInfo = Typ.GetField(eventName & "Event", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)

    Dim Prop As Reflection.PropertyInfo = Evt.FieldType.GetProperty("Method", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)

    Dim Target As Reflection.PropertyInfo = Evt.FieldType.GetProperty("Target", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public)

    Dim MI As Reflection.MethodInfo = Prop.GetValue(Evt.GetValue(objWithEvent), Nothing)

    MI.Invoke(Target.GetValue(Evt.GetValue(objWithEvent), Nothing), params)

    End Sub

    Wednesday, November 15, 2006 11:34 PM
  • OK.  Here's a cleaner sample which handles events with multiple subscribers:

    Public Sub Raise2(ByVal objWithEvent As Object, ByVal eventName As String, ByVal params() As Object)

    Dim Typ As Type = objWithEvent.GetType()

    Dim EvtDlg As MulticastDelegate = Typ.GetField(eventName & "Event", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).GetValue(objWithEvent)

    Dim Dlgs() As [Delegate] = EvtDlg.GetInvocationList()

    For Each Dlg As [Delegate] In Dlgs

    Dlg.Method.Invoke(Dlg.Target, params)

    Next

    End Sub

    Thursday, November 16, 2006 2:23 PM
  • Thanks. I had to make one small modification and it works. "Event" is not being appended to the eventName. I'm using c# 2.0. I wonder if the vb.net compiler is appending the "Event" to the name.

    Saturday, November 18, 2006 12:46 AM
  • Thanks for the VB example. Seems a lot of folks are stuck on this issue.

    Here is a c# flavor of it.

          public event EventHandler<EventArgs> MyEventToBeFired;

            public void FireEvent(Guid instanceId, string handler)
            {

                // Note: this is being fired from a method with in the same class that defined the event (i.e. "this").


                EventArgs e = new EventArgs(instanceId); 

                MulticastDelegate eventDelagate =
                      (MulticastDelegate)this.GetType().GetField(handler,
                       System.Reflection.BindingFlags.Instance |
                       System.Reflection.BindingFlags.NonPublic).GetValue(this); 

                Delegate[] delegates = eventDelagate.GetInvocationList();

                foreach (Delegate dlg in delegates)
                {
                    dlg.Method.Invoke(dlg.Target, new object[] { this, e }); 
                }
            }

            FireEvent(new Guid(),  "MyEventToBeFired");

    Wednesday, November 22, 2006 4:34 PM
  • Hi Could you post a c# sample? I am just a bit curious to look at your current implementation. I've tried several samples, even with GetField(), and I always get null back.

    Thank You,

    Julien

     

    Tuesday, December 05, 2006 12:11 AM