我有以下代码:
var s = Observable
.StartAsync(tnk => CERNWebAccess.GetWebResponse(reqUri))
.SelectMany(resp => Observable.StartAsync(tkn => resp.Content.ReadAsStringAsync()))
.Select(ParseToMD);
ParseToMD非常简单:
private static IDocumentMetadata ParseToMD(string marc21XML)
{
return MARC21Parser.ParseForMetadata(marc21XML);
}
不幸的是,ParseForMetadata抛出异常是非常合法的。我非常希望能够使用正常的Rx技术来处理异常。例如:
var goodOrEmpty = s.Catch(Observable.Empty<Tuple<PaperStub, PaperFullInfo>>());
如何正确保护Select调用,以便将异常正确转换为IObservable On Error?我也需要为其他人做这件事(StartAsync)。
答案 0 :(得分:1)
我遵循的模式与处理异常的标准方式略有不同。仅仅因为选择引发异常并不一定意味着订阅是坏的。下一个活动可能没问题。
请注意,在RX中,当触发OnError时,意味着订阅必须才会终止。
我所做的是将我的选择包装在monadic Exceptional类型中以执行以下操作
Exceptional<IDocumentMetadata> s = Observable
.StartAsync(tnk => CERNWebAccess.GetWebResponse(reqUri))
.SelectMany(resp => Observable.StartAsync(tkn => resp.Content.ReadAsStringAsync()))
.SelectExceptional(ParseToMD);
如果你只是想跳过那些不好的那些
s.SelectMany(s=>s)
或者您可以将其投影为
var Exceptional<ProcessedDocumentType> =
s.Select(document => ProcessDocument(document))
如果需要从Exceptional类型中提取异常,可以使用属性
执行此操作bool HasException
Exception Exception
要获取该值,您可以访问该属性
T Value
但是,如果您只是使用好的值并且不需要例外,那么您应该使用Select和SelectMany。
我的实施基于
答案 1 :(得分:1)
根据您的评论,我不得不怀疑您是否看到使用StartAsync
而不是FromAsync
的效果。这些方法的一个重要细节不同;前者在评估后立即运行一次 - 即无论在任何数量的订户之前和之前它都运行一次。如果没有订阅者并且它会抛出,则会出现未观察到的异常。与订阅时每个订阅者调用的FromAsync
对比。