tags:

views:

194

answers:

2
public class a
{
   public event eventhandler test;
   public void  RaiseTest(){//fire test}
}

Is it possible to raise test on this class, from outside this class, without calling the method?

Basically I have a large number of events which must be raised based on an external source, and do not want to create a Raise() function for each one.

Is it possible to create a generic Raise() that accepts the event to be raised as a parameter? therefore it would still be called from inside the class?

+2  A: 

Is it possible to raise test on this class, from outside this class, without calling the method?

Short answer : no.

Only the class declaring the event can raise it

Is it possible to create a generic Raise() that accepts the event to be raised as a parameter? therefore it would still be called from inside the class?

I don't think so, at least not easily... Even using reflection, there is no EventInfo.Invoke method. AFAIK, the only way to raise the event is statically from within the class

EDIT: actually it can be done (see Reed's answer), but with the limitation that the app has to run in full trust.

Thomas Levesque
Thomas: See my answer for how to handle this via reflection. In full trust, you can actually do it from outside of the class, as well. In partial trust, you could set it up to call this as a method that took the event name as a parameter.
Reed Copsey
+3  A: 

You can do this via Reflection, but it is less than obvious. If you declare an event in C#, a field will be added to the class with the event name + "Event". If you call GetValue on the field, it will return a MulticastDelegate instance.

Once you have the MulticastDelegate, you can get the invocation list, and invoke each member in turn:

EventArgs e = new EventArgs(myClassInstance);  // Create appropriate EventArgs

MulticastDelegate eventDelagate = 
    this.GetType().GetField(theEventName + "Event",
    System.Reflection.BindingFlags.Instance | 
    System.Reflection.BindingFlags.NonPublic).GetValue(myClassInstance) as MulticastDelegate;

Delegate[] delegates = eventDelagate.GetInvocationList();
foreach (Delegate del in delegates) {  
      del.Method.Invoke(del.Target, new object[] { myClassInstance, e }); 
}

Note that this requires getting a NonPublic field from the instance, so it will only work in full trust, and is very limited.

Is it possible to create a generic Raise() that accepts the event to be raised as a parameter? therefore it would still be called from inside the class?

Yes. It would be fairly easy to modify the above code to do this. Just replace "myClassInstance" with this. This will actually allow this to work properly in full trust, as well, since the NonPublic BindingFlag will no longer be an issue.

Reed Copsey
the generic method runs into the problem that the event cannot be passed as a property, giving you the error "must only occur on the left hand" etc. The solution is to remove the event keyword, the event still works as normal, but can be passed around without issue, and raised generically.
Jason Coyne
oh, very nice trick :) I didn't know about the XXXEvent field, I guess it is automatically generated by the compiler ?
Thomas Levesque
Thomas: Yes. @Gaijin: Why do you need the event passed as a property? Here, I'm using the event by name...
Reed Copsey