2012-01-17 8 views
6

私はViewModels(Silverlightおよび/またはWp7アプリケーション)でイベント処理を簡単にするためにReactive Extensionsを使用しています。単純化のための私は私のVMのctorの中で、このようなラインを持っているとしましょう:IObserversの処分はどうすればよいですか?

Observable.FromEvent<PropertyChangedEventArgs>(
          h => MyObject.PropertyChanged += h, 
          h => MyObject.PropertyChanged -= h) 
    .Where(e=>e.PropertyName == "Title") 
    .Throttle(TimeSpan.FromSeconds(0.5)) 
    .Subscribe(e=>{/*do something*/}); 

これは、IDisposableのオブジェクトを返し、配置された場合が解除されます。(私はこの仮定の通りですか?)
私がそれを参照していなければ、遅かれ早かれそれが収集され、ハンドラは登録解除されます。

通常、私のVMにはList<IDisposable>があります。サブスクリプションを追加しますが、正しいRx方法で何かをやっていないかのように、私はそれについて汚れています。

このような状況で推奨されるパターンは何ですか?

答えて

9

あなたの最初の仮定は正しいです、IDisposableは登録を解除するためのものです。ただし、オブザーバーが収集されないようにIDisposableへの参照を保持する必要はありません。 IObservableは、オブザーバがそのメソッドを呼び出すことができるようにオブザーバへの参照を保持する必要があるため、オブザーバが存続している限り、オブザーバを生かしておく必要があります。

洞察力のある読者は、観察可能なものが収集されないと仮定しているので、私は少し質問をしています。その問題に対処するために、舞台裏で何が起こっているのかについていくつか合理的な推測をしましょう。最初のオブザーバブルはイベントを購読しています。つまり、イベントのあるオブジェクトには、購読してから購読を停止するまでのオブザーバーの参照があります。 Rxオペレータはある時点でソースに加入していなければならないので、イベントオブザーバには、スロットルオブザーバへの参照があるWhere observerへの参照があると仮定できます。

私たちは退会していないので、イベントでのオブジェの生活にオブザーバーの人生を結びつけます。あなたのプログラムを十分に理解していなければ、それは私が行くことができるチェーンの遠い方ですが、観察可能なものの寿命を決めるだけで十分だと思います。

これは実際には、標準の.NETイベント、つまりすべてのイベントサブスクライバを維持しているオブジェクトが潜在的な「メモリリーク」を指摘し、2番目の質問につながります。 IDisposableへの参照を保持しないと、そのイベントから退会することは決してできず、関連するビューを閉じた後でも、オブジェクトは通知を引き続き受信します。イベントソースがビューより長生んでいない場合は問題ありませんが、使い捨てのを使用することをお勧めします。

これについては何も「un-Rx」はありません。また、Rxには、好きなときにリストの代わりに使う良いクラスが含まれています。System.Reactive.Disposables.CompositeDisposable

+0

.NETメモリのイベントリークについて知っていますが、IObservableがオブザーバをFinalizeに配置しても問題はありません。なぜなら、finalizeはここで呼び出されないからです...ありがとうございます! – TDaver

+1

'IObservable 'がどのように動作して使用されるべきかを指定していたなら、正しく書かれたすべての消費者は返された 'IDisposable'のどこかへの参照を保持しなければならないと指定し、実装は自由に考えるべきです( )関連付けられた 'IDisposable'が範囲外になったサブスクリプションをキャンセルします。 – supercat

-1

通常、IDisposableインターフェイスを実装し、使い捨てのメンバーをここに配置します。

+0

私のVMはIDisposableを実装するのですか?誰がそれを処分するのだろうか?(または、ファイナライザを使用してdispose-patternを実装する必要がありますか?) – TDaver

+0

@TDaverクライアントはDisposeを呼び出すことに責任があり、オブジェクトをどのようにインスタンス化するかによって異なります。 –

6

ギデオンはここでは間違っています。 RxがIDisposableをどのように使用するかのセマンティクスは、典型的な.NETとは異なります。 Subscribeから返されたIDisposableは、より早くをIObservableの終了よりも購読を取り消す場合に使用します。これをやりたくない場合は、余分な使い捨て管理のすべてでコードを複雑にする必要はありません。

+0

イベントソースがOnCompletedを呼び出すと、すべてが自動的に退会しますか? – TDaver

+0

TDaver:はいそれは –

+0

ええ、しかし、 "イベント"はこれまでに完了しません。これはObservable Streamsなどを使用するためのものです。だから私はGideonのアイデアが必要ですが、あなたも正しいことは間違いありません。 – TDaver

関連する問題