转发/转发.NET事件

时间:2009-06-01 14:23:50

标签: c# .net events

我的类有一个外部对象将订阅的事件:

public event EventHandler<MessageReceivedEventArgs> MessageReceived;

但是,在其自己的线程上运行的内部Listener对象实际上将发起该事件。

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

我倾向于在Listener上创建一个具有相同签名的事件,并在主类中订阅它以便在MessageReceived上引发它。这看起来有点麻烦,所以我想知道是否有一种简洁/惯用的方式来转发这样的事件。

3 个答案:

答案 0 :(得分:22)

您可以使用事件add/remove accessors,以便将连接到面向外部事件的事件“转发”到内部侦听器

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

这意味着你需要在监听器中创建一个事件,但好处是没有其他的管道来连接事件。

答案 1 :(得分:1)

您可以使用事件执行此操作,或者您可以在主类中创建一个名为ReceiveMessage()的方法,并从侦听器调用该方法(然后从那里引发事件)。

答案 2 :(得分:1)

如上所述,您可以使用添加和删除处理程序的自定义订阅逻辑。

请注意,此设计存在问题。您指定您的侦听器在其自己的线程中引发事件。默认情况下,将在引发事件的线程上调用处理程序(在您的情况下,是监听器的线程)。你有几个选择。

  • 如果你不在乎让Listener的线程执行回调。只是按原样调用事件(但是如果事件处理程序需要一段时间才能执行,则可以阻止侦听器线程,或者如果事件处理程序抛出未处理的异常,则可以阻塞)
  • 如果你希望处理程序在不同于Listener线程的线程中运行,但是只要它不在监听器中就不关心哪些线程:在实际调用处理程序的OnXXX方法中,获取调用的调用列表事件并对线程池中的每个处理程序进行排队。
  • 如果你想在特定的线程中调用处理程序:有点棘手,你必须使用一些SynchronizationContext(Winforms中的WindowsSynchronizationContext,其他情况下的自定义,等等)。

Roy Osherove的博客文章显示了几种执行异步调用的方法:http://weblogs.asp.net/rosherove/pages/DefensiveEventPublishing.aspx (但我不会在委托上使用异步调用,而是直接依赖ThreadPool来调用委托)。