Tomer Gabel's annoying spot on the 'net RSS 2.0
# Tuesday, October 25, 2005

So I found myself in the predicament where a particular class I was using had multiple event sources and I was attempting to fire those events. I encountered two issues, the first of which was that I was trying to invoke the delegates from an outside class, which is impossible even though they're public:

An event can be used as the left-hand operand of the += and -= operators (Section 7.13.3). These operators are used, respectively, to attach event handlers to or to remove event handlers from an event, and the access modifiers of the event control the contexts in which such operations are permitted.

Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.

(via MSDN)

This means I had to implement an OnEvent() triger method on the provider class for all events, even though the provider class was intended merely as a container and the events were intended to be fired elsewhere (think of a remotable event container and a seperate execution piepline). This meant I had to provide a lot of boiler-plate code in both consumer and provider classes to make use of these events. I would've written a generic method to handle this which accepts a Delegate parameter; enter the second issue: you'll notice that a non-specialized delegate (Delegate as opposed to, say, an instance of AsyncDelegate) does not have a BeginInvoke method. After a little research I've found some inspiration in Eric Gunnerson and Juval Lowy's classic TechNet presentation on C# best practices, however that particular implementation wasn't convenient for my uses, nor was it compliant with .NET 1.1 specifications (which require that you call EndInvoke on any asynchronous invocation to avoid resource leaks). I eventually went on to write a class that'll do the work for me.

The basic idea is to call the delegate's BeginInvoke and EndInvoke methods via Reflection. To invoke a method via Reflection you (obviously) require an invocation target; this wouldn't be an issue if the target hadn't been an event. Apparently the EventInfo class returned by Type.GetEvent() has no provision for obtaining an actual instance; instead, you have to obtain the event instance as though it were a field. Check out the following code:

// Gather requisite Reflection data

private Type m_handler;
private object m_eventInstance;

...

m_eventInstance = target.GetType().GetField( eventName, BindingFlags.Instance | BindingFlags.NonPublic ).GetValue( target );
m_handler       = target.GetType().GetEvent( eventName, BindingFlags.Instance | BindingFlags.Public    ).EventHandlerType;

// Call BeginInvoke

m_handler.InvokeMember(
"BeginInvoke",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod,
null,
m_eventInstance,
paraList.ToArray()
);

You can find a complete AsyncHelper class and associated (very minimal) example code here. Note that at current delegates with out or ref parameters are not supported; these could be inferred by Reflection and added to the EndInvoke method call, but I fail to see how calling such delegates asynchronously in a generic fashion would be useful.

Tuesday, October 25, 2005 5:59:40 PM (Jerusalem Standard Time, UTC+02:00)  #    Comments [3] -
Development
Tracked by:
http://www.ayende.com/Blog/2005/10/25/GenericFiringOfAsynchoronousEvents.aspx [Pingback]
Tuesday, October 25, 2005 6:56:56 PM (Jerusalem Standard Time, UTC+02:00)
If I understand correctly, you want to have a generic events source? That is it sole responsebility?
Do you really need to use events in this case?

container.Subscribe("SomeEvent", new SomeEventHandler(myEventHandler));

and then, later, you just call:

container.Fire("SomeEvent", "my message");

Internally you hold a hashtable of all the events and all the subsribers, you can even make it totally customizable so you can add remove events in run time.
Wednesday, October 26, 2005 12:33:35 AM (Jerusalem Standard Time, UTC+02:00)
Well what actually happens is that I have a class implementing a remotable interface ISomethingProvider; it has quite a few events and also several methods (for bidirectional communication). I have a concrete class implementing this interface. There is a seperate execution pipeline (part of an abstract virtual machine) whose job is to fire events on any number of instances of said concrete class. There are approximately 20 different events. I _could_ go the route of another layer of indirection (i.e. OnEvent method fires the Event event of said class), or alternatively provide a different event subscription technique as in your article; however that would mean re-doing a very convenient bit of C# syntactic sugar (event subscription). This is a minor hack, but I think it looks better overall (plus, I worked it into the VM's job scheduler as a wait handle so it's pretty slick anyway).

Wednesday, October 26, 2005 12:38:04 AM (Jerusalem Standard Time, UTC+02:00)
Upon re-reading your blog post I guess I misunderstood; I see what you mean. Instead of BeginInvoking I create a sort of "shim" delegate that I run asynchronously, which invokes the parameter delegate. This is more in-line with what Juval Lowy and Eric Gunnerson were describing in their presentation; I'll give this a try and see if it works better in my case. Thanks!
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Live Comment Preview
Me!
Send mail to the author(s) Be afraid.
Archive
<May 2013>
SunMonTueWedThuFriSat
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
All Content © 2013, Tomer Gabel
Based on the Business theme for dasBlog created by Christoph De Baene (delarou)