web-dev-qa-db-ja.com

反応性の観察可能なサブスクリプションの処分

1つのアイテムしか返さないことがわかっているIObservableにアクセスできる場合、これは機能し、最適な使用パターンですか?

IDisposable disposable = null;
disposable = myObservable.Subscribe(x =>
  {
     DoThingWithItem(x);
     if (disposable != null)
     {
       disposable.Dispose();
     }
  });
22
Noob

免責事項:私もまだRxを学んでいます。したがって、私は実際には専門家ではありませんが、Subscribeによって返される使い捨てはサブスクリプションのサブスクリプションを解除するだけだと思います。また、あなたの場合のようにソースが完了すると、サブスクリプションの解除は自動的に行われます。したがって、Disposeは冗長であり、安全に削除できると思います。

詳細については、これに対する回答を参照してください 質問

14
Ilian Pinzon

Subscribe拡張メソッドによって返されるディスポーザブルは、監視対象beforeから手動でサブスクライブを解除できるようにするためだけに返されます。

オブザーバブルが-OnCompletedまたはOnErrorのいずれかで完了した場合、サブスクリプションは既に破棄されています。

このコードを試してください:

_var xs = Observable.Create<int>(o =>
{
    var d = Observable.Return(1).Subscribe(o);
    return Disposable.Create(() =>
    {
        Console.WriteLine("Disposed!");
        d.Dispose();
    });
});

var subscription = xs.Subscribe(x => Console.WriteLine(x));
_

上記を実行すると、「Disposed!」と表示されます。サブスクリプションで.Dispose()を呼び出す必要なしに、オブザーバブルが完了すると、コンソールに書き込まれます。

注意すべき重要な点の1つは、ガベージコレクターが監視可能なサブスクリプションで.Dispose()を呼び出すことはないため、サブスクリプションがない場合はmust破棄します(またはサブスクリプションが範囲外になる前に自然に終了しました。

これを例にとってみましょう:

_var wc = new WebClient();

var ds = Observable
    .FromEventPattern<
        DownloadStringCompletedEventHandler,
        DownloadStringCompletedEventArgs>(
            h => wc.DownloadStringCompleted += h,
            h => wc.DownloadStringCompleted -= h);

var subscription =
    ds.Subscribe(d =>
        Console.WriteLine(d.EventArgs.Result));
_

ds observableは、サブスクリプションがある場合にのみイベントハンドラーにアタッチし、オブザーバブルが完了するかサブスクリプションが破棄された場合にのみデタッチします。これはイベントハンドラーであるため、オブザーバブルはさらにイベントを待機しているため完了しません。したがって、イベントから切り離す唯一の方法は破棄です(上記の例の場合)。

FromEventPattern observableがあり、1つの値しか返さないことがわかっている場合は、サブスクライブする前に.Take(1)拡張メソッドを追加して、イベントハンドラーを自動的にデタッチできるようにしてから、サブスクリプションを手動で破棄する必要はありません。

そのようです:

_var ds = Observable
    .FromEventPattern<
        DownloadStringCompletedEventHandler,
        DownloadStringCompletedEventArgs>(
            h => wc.DownloadStringCompleted += h,
            h => wc.DownloadStringCompleted -= h)
    .Take(1);
_

これがお役に立てば幸いです。

55
Enigmativity

Take関数は、まさにあなたが探していることを実行します。この場合、Take(1)

4

一部のコメントとは対照的に、OnNext内からサブスクリプションを破棄することはまったく珍しいことではありません。

OnCompletedOnErrorでの廃棄は、Subscribe拡張メソッドが作成するラップされたサブスクリプションによって行われるのは事実ですが、サブスクライブを解除することもできます。あなたが観察している値(あなたの場合のように:最初のもの)。 1つの値しか生成しないことがわかっているオブザーバブルが常にあるとは限りません。

問題は、サブスクライブした後にのみIDisposableを取得することです。オブザーバブルは、購読を解除するためにOnNextを返す前であっても、IDisposableにコールバックする場合があります(使用するISchedulerなどによって異なります)。

この場合、_System.Reactive.Disposables.SingleAssignmentDisposable_が便利です。遅れて割り当てる可能性のあるIDisposableをラップし、それまでにSingleAssignmentDisposableがすでに破棄されている場合は、割り当て時にすぐに破棄します。また、プロパティIsDisposedを持ち、最初はfalseであり、Dispose()が呼び出されるとtrueに設定されます。

そう:

_IObservable<string> source = ...;

var subscription = new SingleAssignmentDisposable();
subscription.Disposable = source.Subscribe(x =>
{
    if (subscription.IsDisposed) // getting notified though I've told it to stop
        return;
    DoThingsWithItem(x);
    if (x == "the last item I'm interested in")
        subscription.Dispose();
});
_
1
tinudu