如何处理从消息处理程序
取消订阅时抛出的异常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;
答案 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}}可确保在单个事件源级别以及事件源中进行序列化。