tags:

views:

222

answers:

3

My class has an event which external objects will subscribe to:

public event EventHandler<MessageReceivedEventArgs> MessageReceived;

However, an internal Listener object, running on it's own thread, will actually be originating the event.

private class Listener
{
    public void Run()
    {
         // events raised here which should be forwarded
         // to parent's MessageReceived
    }
};

My inclination is to create an event with the same signature on the Listener, and subscribe to it in the main class in order to raise it on MessageReceived. This seems a little cumbersome, so I was wondering if there is a neat/idiomatic way of forwarding events like this.

+1  A: 

You could do that with an event, or you could create a method in your main class called ReceiveMessage() and call that from the listener (and then raise the event from there).

Jon B
+11  A: 

You can use event add/remove accessors so that events wired to the external-facing event are "forwarded" to the internal listener

public event EventHandler<MessageReceivedEventArgs> MessageReceived {
   add { this.listener.MessageRecieved += value; }
   remove { this.listener.MessageRecieved -= value; }
}

This means you need to create an event in the listener, but the benefit is that there is no other plumbing to wire up the event.

Ryan Emerle
This is a nice solution, but be aware that the event handler will receive the Listener instance as the sender argument, which may be a problem...
Thomas Levesque
Nice, I like it!
marijne
Also a good point about the sender...
marijne
You can pass the parent object into the Listener and call MessageReceived( parentObject, EventArgs.Empty ). In short, you can set the sender to whatever you want.
Ryan Emerle
+1  A: 

As it has been answered, you can have a custom subscribing logic using add and remove handlers on your event.

Note that this design has a problem as is. You specify that your listener is raising the event in its own thread. By default, the handlers will be called on the thread which raised the event (in your case, the Listener's thread). You have several options.

  • If you don't care having the Listener's thread executing the callbacks. Just call the event as is (but your Listener thread can be blocked if an eventhandler takes a while to execute, or just die if an event handler throws an unhandled exception)
  • If you want the handlers run in threads different than the Listener's thread, but don't care in which threads as long as it's not in the listener : in the OnXXX method that actually calls the handlers, get the invocation list of the event and queue each handler in the threadpool.
  • If you want the handlers to be called in specific threads : a bit tricky, you have to use some SynchronizationContext (WindowsSynchronizationContext in Winforms, a custom one in other cases, etc.)

There's a blog post by Roy Osherove showing several ways to do the async calls : http://weblogs.asp.net/rosherove/pages/DefensiveEventPublishing.aspx (but I wouldn't use the async calls on delegates and instead directly rely on the ThreadPool to call the delegates).

Yann Schwartz