在不停止序列的情况下处理Reactive Extensions中的异常

时间:2012-11-09 15:07:56

标签: c# .net exception-handling system.reactive

为什么RX具有以下语法OnNext* (OnError|OnCompleted)?而不是(OnNext|OnError)* OnCompleted?从实现的角度来看这是非常清楚的(这也与IEnumerableyield有共同的语义),但我想与现实生活情况不同。在现实生活中 - 生产者生成混合的数据流和异常(异常不会破坏生产者)。

问题: 如果我理解正确,唯一可能的解决方案是使可观察的返回复杂数据结构从初始数据和生成的异常(Observable.Timestamp().TimeInterval()具有相似的概念)相结合,还是有其他选择?


目前我找到了以下解决方案: 在可观察的生产者内部,我手动处理exeptions并将它们传递给以下数据结构,这是我可观察的结果

public class ValueOrException<T>
{
    private readonly Exception ex;
    private readonly T value;

    public ValueOrException(T value, Exception ex)
    {
        this.value = value;
        this.ex = ex;
    }

    public ValueOrException(T value)
    {
        this.value = value;
    }

    public T Value
    {
        get { return this.value; }
    }

    public Exception Ex
    {
        get { return this.ex; }
    }
}

3 个答案:

答案 0 :(得分:6)

如果消费者知道是否预期Exception,那么我说抛出异常在这里是不正确的。

你实际上是在试图传达状态或逻辑,这些异常并不意味着要做。例外意味着将系统(或至少是当前操作)暂停,因为发生了一些代码本身并不知道如何从中恢复的事情。

在这种情况下,恰好是Exception部分的业务逻辑/状态,但这并不意味着你可以扔掉它们。您需要将它们传递给您的消费者,然后由您的消费者处理它们。

Tuple<T, Exception>可以在这里工作,但是类型(以及属性)缺乏特异性通常是混乱的,所以我建议创建一个专用类型来传达你的结果操作并通过IObservable<T>公开。

答案 1 :(得分:1)

OnError意味着发生了不可恢复的错误,因此应该重置流。在恢复之后,下一个事件在异常之前发生的事件的背景下没有意义。

例如,考虑一下事件流:

  • 用户加入了聊天
  • 用户加入了聊天
  • !! 聊天崩溃,所有用户都被踢了
  • 用户加入了聊天

现在,流消费者使用聚合功能显示聊天的数量。最后应该显示什么?当然是1,而不是3.我们应该在异常后从头开始计数。

答案 2 :(得分:0)

ValueOrException类似于函数式编程中的Either类型。你刚刚交换了Left和Right。按惯例,右用于成功,左用于失败。