1

IObservable<T>.Subscribeのオーバーロードの1つは

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

内部的には、これによりAnoymousObserver<T>IObservableにが作成および登録されます。渡された例外を再スローする単純なラムダである未指定のonErrorパラメーターが設定されます。Stubs.Throw

内部的には、IObservableのオブザーバーはすべて、タイプObserverの単一のインスタンスに含まれています。これはのコードですObserver<T>.OnError

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

Stubs.Throwは例外をスローするため、そのオブザーバーのOnErrorからの例外は、foreachループと_observers.Data内の他のオブザーバーを通過します。OnErrorが呼び出されることはありません。例外自体はRx内のどこかに飲み込まれます。

Observer <T> .OnErrorはobserver.OnErrorをtry-catchでラップするか、Stubs.Throwは例外をスローする代わりに飲み込む必要があるように思われます。onErrorパラメーターを渡さないことにより、IObservable.Subscribeのユーザーは、そのサブスクライブに対してのみエラーが無視されることを望んでいます。独自のonErrorコールバックで登録された他のサブスクライバーは影響を受けないはずです。

(私はすでにCodeplexにバグを報告しましたが、トラッカーは見捨てられているように見えるので、これを正しく理解しているかどうかを確認するためにSOにも依頼したいと思いました。)


更新:アスティの答えは正しいです。リンクされたバグレポートに関する議論で、davedevはIEnumerableとの類似性を示し、例外を未処理でスローするデフォルトが、catchブロックなしでIEnumerableを反復するデフォルトと同等である方法を示しました。

オブザーバブルが特定の例外を致命的と見なすべきではないと判断した場合、OnErrorを使用してこれを伝達するべきではありません。OnErrorを呼び出すと、そもそもobservableに重大な問題が発生したことを意味するため、OnErrorが実行される保証はありません。代わりに、observableはIObservable < Either <T、Exception >>として定義できます( Observable2.Retryでの使用例)。

4

1 に答える 1

1

これは実際には予想される動作です。

OnErrorは、オブザーバーに例外がスローされたことを示すために呼び出されるメソッドではありませんOnNext。これは、オブザーバブルシーケンスの異常終了を示すためのものです。デフォルトのOnError実装では、通知がObservableモナドから移行するときに例外がスローされます。

Rx設計ガイドラインを読むと、Rxコントラクトと例外処理がより明確になります。パイプラインに沿ったエラー処理、およびその他のIEnumerable/IQueryableのような動作については、を参照してくださいSubscribeSafe

于 2013-01-21T12:10:47.703 に答える