2011-10-09 7 views
18

私が知っているIObservableへのアクセス権がある場合、これは1つのアイテムのみを返すことになります。反応性監視対象サブスクリプションの廃棄

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

に配置されたオブジェクトがスコープ内にあるという事実は、それ悪いスタイルになり私見。何か不足していますか? –

+0

これは、ディスポーザブル変数が有効範​​囲外になる前にmyObservableが起動した場合に、「使い捨て」変数を破棄できることを意味しますか?このオブジェクトを処分するより良いパターンは何ですか? – Noob

答えて

9

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

詳細はquestionの回答をご覧ください。

4

Take機能は、あなたが探しているものとまったく同じです。この場合、Take(1)

+2

あなたが言うことは証明できますか? –

46

延長方法Subscribeによって返却された使い捨て品は、観察可能なものが終了する前に、観察可能なから手動で退会できるように返されます。が自然終了します。

観測可能リストが完了すると、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)); 

このコードを試してみてください「配置されているの!」サブスクリプションで.Dispose()というコールを必要とせずに観測が完了するとコンソールに書き込まれます。注意すべき

一つ重要なこと:あなたのサブスクリプションがスコープの外に出る前に、彼らが持っていない(または持たないかもしれない)場合、ガベージコレクタは、サブスクリプションのあなたがそう必須処分、観察可能なサブスクリプションに.Dispose()を呼び出すことはありませんが、自然に終わりました。

には、例えば、これを取る:

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それが加入していると、観察完了またはサブスクリプションが破棄されたときにのみ取り外します場合にのみ、イベントハンドラに付着する観測可能。それはイベントハンドラであるため、オブザーバブルは、より多くのイベントを待っているため、決して完了しません。したがって、ディスポジションはイベントから切り離す唯一の方法です(上記の例の場合)。

あなたが知っているだけで、これまで一つの値を返すことに観察FromEventPatternを持っている場合、イベントハンドラが自動的にデタッチした後、手動で処分する必要はありませんできるようにサブスクライブする前に、.Take(1)拡張メソッドを追加するのが賢明ですサブスクリプションそのよう

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

私はこのことができます願っています。

+0

ありがとう!私はこの正確な問題(私が欲しいだけのイベント)を持ち、 'Take(1)'は完璧な解決策です。 – moswald

+2

@moswald注意 'FirstAsync()'も同じことをします。 – lobsterism

+1

'ガベージコレクタは、観測可能なサブスクリプションで.Dispose()を呼び出すことはありません。 ' - これは私がここにいたものです。ありがとう! –

0

いくつかのコメントとは対照的に、OnNextからの購読を処理することは珍しくありません。

Subscribe拡張メソッドが作成するラップされたサブスクリプションによって、OnCompletedOnErrorに処分されたことが本当ですが、あなたの観察している値(最初のもののようなもの)に基づいて、 。 1つの値だけを生成することが知られているオブザーバブルを常に持っているとは限りません。

登録した後に初めてIDisposableが届くという問題があります。あなたがISchedulerのようなものに依存して、IDisposableを退会する前でさえ、観察可能な人はOnNextに戻ることがあります。この場合、System.Reactive.Disposables.SingleAssignmentDisposableが便利です。遅く割り当てられるIDisposableをラップし、SingleAssignmentDisposableがすでに処分されている場合は、直ちに処分します。また、最初にfalseであるプロパティIsDisposedを持ち、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(); 
}); 
関連する問題