RX FromEvent <t>方法</t>中的异常处理

时间:2014-11-17 09:32:01

标签: c# exception-handling event-handling system.reactive reactive-programming

如何处理从消息处理程序

取消订阅时抛出的异常
var rawSource = Observable.FromEvent<EMSMessageHandler, EMSMessageEventArgs>(
            handler => ((sender, e) => handler(e)),
            a => this._topicSubscribers.ForEach( s => s.MessageHandler += a ),
            a => this._topicSubscribers.ForEach( s => s.MessageHandler -= a));
        return rawSource;

在这段代码中,我有时会从MessageHandler中抛出异常,因为&#34; Illegalstateexception:{&#34; Consumer is closed&#34;}&#34;

2 个答案:

答案 0 :(得分:3)

事件通常不会抛出,因此源可能是错误的行为。如果您可以在源头修复它,那么就这样做。

否则,你要么必须抓住并吞下错误:

a => this._topicSubscribers.ForEach(s => 
{
  try
  {
    s.MessageHandler += a;
  }
  catch
  {
  }
})

可能不理想,或者只是不使用FromEvent方法:

return Observable.Create<EventPattern<EMSMessageEventArgs>>(observer =>
{
  EMSMessageHandler handler = (sender, e) => 
    observer.OnNext(new EventPattern<EMSMessageEventArgs>(sender, e)));

  try
  {
    _topicSubscribers.ForEach(s => s.MessageHandler += handler);
  }
  catch (Exception ex)
  {
    try
    {
      _topicSubscribers.ForEach(s => s.MessageHandler -= handler);
    }
    catch { }

    observer.OnError(ex);
  }

  return Disposable.Create(() =>
  {
    try
    {
      _topicSubscribers.ForEach(s => s.MessageHandler -= handler);
    }
    catch { }
  });
});

请注意,Rx需要序列化通知(Rx Design Guidelines中的§4.2),因此您必须确保所有_topicSubscribers按顺序引发事件,而不是同时发生。如果你不能,那么你必须自己同步所有对observer.OnNext的呼叫,可能是通过获取一个锁。

更新:要明确,无论您使用的是FromEvent还是Create,都需要序列化,因此即使您选择像我的第一个示例那样简单地吞下例外,你仍然需要确保源不会同时引发事件;如果你做不到,那么无论如何你都被迫使用我的Create示例。 FromEvent不会为您执行此操作。

答案 1 :(得分:3)

这样使用FromEvent是因为Dave引用Rx中需要序列化的所有原因而要求麻烦。

但是,假设事件并未在每个事件源中同时发生(我相信这是EMS MessageConsumer的情况),我只会在FromEvent之后而不是在其中进行聚合,并且让Rx做繁重的工作:

var sources = new List<IObservable<EMSMessageEventArgs>();     

foreach(var topicSubscriber in this._topicSubscribers.ToList())
{
    var source = Observable.FromEvent<EMSMessageHandler, EMSMessageEventArgs>(
        handler => ((sender, e) => handler(e)),
        h => topicSubscriber.MessageHandler += h,
        h => topicSubscriber.MessageHandler -= h)
        .Synchronize();
}

rawSource = sources.Merge();

这样Merge将正确地聚合和序列化各个源 - 但是, 仍然可以在各个事件中并发。实际上,我并不认为FromEvent在个别来源中同时被提出的事件会强调Merge。但是,Sychronize()可能不会如此宽容,在这种情况下,使用上面的{{1}}可确保在单个事件源级别以及事件源中进行序列化。