WeakEventパターンを考える
WPFにWeakEventパターンというものがあります。これについてすこし考えてみたいと思います。まずはMSDNからの抜粋でどのようなものか見てみましょう。
一般的なアプリケーションでは、イベント ソースにアタッチされているハンドラが、このハンドラをソースにアタッチしたリスナ オブジェクトとの関連によって、破棄されないことがあります。このような状況は、メモリ リークにつながる可能性があります。Windows Presentation Foundation (WPF) では、特定のデザイン パターンが導入されており、このデザイン パターンを使用して、特定のイベントの専用マネージャ クラスを提供し、そのイベントのリスナにインターフェイスを実装することによって、この問題に対処できます。このデザイン パターンは、WeakEvent パターンと呼ばれます。
通常、リスナのイベント ハンドラをアタッチすると、リスナはオブジェクトの有効期間を持ちますが、この有効期間はソースのオブジェクトの有効期間に影響されます (イベント ハンドラが明示的に削除されない場合)。ただし、特定の状況では、リスナのオブジェクトの有効期間を、ソースの有効期間によってではなく、アプリケーションのビジュアル ツリーに現在属しているかどうかなどの別の要素によってのみ制御したい場合もあります。ソース オブジェクトの有効期間がリスナのオブジェクトの有効期間を超える場合、常に通常のイベント パターンによってメモリ リークが発生します。つまり、このリスナは想定した以上に長く維持されます。
WeakEvent パターンの実装は、主にコントロール作成者にとって意味があります。それは、コントロールの作成者には、作成したコントロールの動作と格納およびそれを組み込むアプリケーションに与える影響に対する主な責任があるためです。これには、コントロール オブジェクトの有効期間の動作 (特に、上に示したメモリ リークの問題への対応) が含まれます。
まとめると『WeakEvent トパターンはWPF上の特定のデザインパターンで、リスナ オブジェクトが想定した以上に長く維持されるメモリリークに対処するもので、主にコントロール作成者にとって意味がある』ということです。
利用範囲を考える
デザインパターンなのでどのような状況下で利用するかを考えます。上記の資料よりポイントをひらうと以下の2つの条件がある場合にこのパターンを利用する状況と判断できます。
-
- ソースがリスナーより長いライフサイクルである
- 明示的にイベントの解除ができない
上記を掘り下げてみましょう。まず前者のソースがリスナーより長いライフサイクルということはソースがリスナー以外の強い参照を持っているということです。いいかえれば以下のような場合にあたります。
-
- ソースがリスナー以外からの参照がある場合
後者はリスナー側に後処理のタイミングが用意されていなくということなで具体的には以下のようになります。
-
- リスナー側でイベント解除できるタイミングの処理(イベントやメソッド)がない
このように考えると適用範囲はある程度絞られる感じがします。実際に適用範囲を表に整理します。
リスナー種別 | ソースのライフサイクルがリスナーよりも | ||||||||||||||||||||||||||||||||||
長い | 同じ | 短い | |||||||||||||||||||||||||||||||||
解除タイミングがある | △ | △ | ? | ||||||||||||||||||||||||||||||||
解除タイミングがない | ○ | △ | ? | ||||||||||||||||||||||||||||||||
リスナー/ ソース | View | Control | ViewItem | ViewModel | Model |
View | C# | C# | C# | C# | C# |
Control | C# | C# | C# | C# | C# |
ViewItem | WeakEvent | WeakEvent+ | WeakEvent+ | WeakEvent | WeakEvent+ |
ViewModel | C# | NG | NG | C# | C# |
Model | NG | NG | NG | C# | C# |
リスナーがViewやControlであれば解除タイミングがあるのでC#で明示的な実装が可能です。ViewModelとModelについてはC#の実装でも良いですがControlやViewItemは参照しないはずです。ViewItemは解除タイミングがないのでソースのライフサイクルが長くなる可能性がある場合はWeakEventを利用します。+が付いているものはソースのライフサイクルが短くなる可能性がありますので必要に応じて解除の仕組みを追加します。
まとめ
WeakEventパターンをどこまで利用するかは個々の事情によって変化すると思いますが、MSDNから推測すると、明示的なイベントの解除が可能か、ソースのライフサイクルの前提はあるかなどを踏まえて使用するのがポイントとになりそうです。