将异常转换为IObservable异常

时间:2014-04-06 10:41:47

标签: exception-handling system.reactive

我有以下代码:

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)。

2 个答案:

答案 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。

我的实施基于

Exception or Either monad in C#

答案 1 :(得分:1)

根据您的评论,我不得不怀疑您是否看到使用StartAsync而不是FromAsync的效果。这些方法的一个重要细节不同;前者在评估后立即运行一次 - 即无论在任何数量的订户之前和之前它都运行一次。如果没有订阅者并且它会抛出,则会出现未观察到的异常。与订阅时每个订阅者调用的FromAsync对比。