【问题标题】:Observer<T>.OnError's assumptions seem to be inconsistent with Stubs.ThrowObserver<T>.OnError 的假设似乎与 Stubs.Throw 不一致
【发布时间】:2013-01-21 00:13:32
【问题描述】:

IObservable.Subscribe 的重载之一是

public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext)

在内部,这会在 IObservable 上创建并注册一个 AnoymousObserver&lt;T&gt;。未指定的onError 参数设置为Stubs.Throw,这是一个简单的lambda,它重新抛出传入的异常。

在内部,IObservable 的观察者都包含在 Observer 类型的单个实例中。这是Observer&lt;T&gt;.OnError中的代码

public void OnError(Exception error)
{
    foreach (var observer in _observers.Data)
        observer.OnError(error);
}

由于 Stubs.Throw 抛出异常,来自该观察者的 OnError 的异常通过 foreach 循环传递,并且 _observers.Data 中的其他观察者永远不会调用其 OnError。异常本身在 Rx 内部的某个地方被吞没了。

在我看来,要么 Observer.OnError 应该将 observer.OnError 包装在 try-catch 中,要么 Stubs.Throw 应该吞下异常而不是抛出它。通过不传递 onError 参数,IObservable.Subscribe 的用户希望仅对该订阅忽略错误。使用自己的 onError 回调注册的其他订阅者应该不受影响。

(我已经在 Codeplex 上提交了bug,但跟踪器看起来很冷清,所以我想我也应该问一下 SO,看看我是否理解正确。)


更新:Asti 的回答是正确的。在关于链接的错误报告的讨论中,davedev 与 IEnumerable 进行了类比,并且默认抛出未处理的异常如何等同于在没有 catch 块的情况下迭代 IEnumerable 的默认值。

如果 observable 确定不应将特定异常视为致命异常,则不应使用 OnError 进行通信。 OnError 不能保证被执行,因为调用它意味着首先观察到的东西出现了严重错误。相反,可以将 observable 定义为 IObservableEither>(Observable2.Retry 中的示例用法)。

【问题讨论】:

    标签: system.reactive


    【解决方案1】:

    这实际上是预期的行为。

    OnError 不是一个被调用来指示在观察者的OnNext 上抛出异常的方法 - 它表示可观察序列的异常终止。默认的OnError 实现将在通知转换出 Observable monad 时抛出异常。

    如果您阅读Rx Design Guidelines,您将对 Rx 合同和异常处理有更清楚的了解。至于管道中的错误处理,以及更多类似IEnumerable/IQueryable 的行为,请查看SubscribeSafe

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 2020-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      相关资源
      最近更新 更多