MEF はMSDNだけみて使ってみたのですが、 もう少し使い勝手が良くならないか勉強しました。
MEF の基本は、実体化したいオブジェクトの取得元となる情報を ComposablePartCatalog クラスから派生した AssemblyCatalog クラス やTypeCatalog クラス を用いてアセンブリやTypeの情報を CompositionContainer というコンテナに登録、このコンテナから実体化する ことまでは直観的にわかりました。
ただ、Get××とかCreate××のような如何にもインスタンス取得できそうなメソッドがなく、 MSDNのサンプルでは container.ComposeParts メソッド 呼び出すことで メンバーに実体が割り当てられるという、あまり使い勝手がよくない状態でした。
当たり前のDIとして、以下のようなことができないのか
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
いろいろわかりました。
まず、container.ComposeParts メソッド を利用しないサービス取得の場合は、Import属性は不要でした。 そもそも、container.ComposeParts メソッド を利用するシーンの方が少ないような気もします。
何はともあれ、PartCreationPolicy属性も付けます。
この属性を付与しない場合、コンテナからインスタンスを取得するとすべて同じインスタンスを返します。
これがデフォルト動作で、これでは困るので先ほどの属性を利用して、実体化する場合は新しいインスタンスとなるように明示します。
次に ExportMetadata属性 でオブジェクトに追加情報を付与します。
以下がサンプルの宣言です。
1 2 3 4 5 6 7 8 9 10 |
|
ExportMetadata属性で、”Priority” という優先度の付加情報を付与しました。
この取得方法が面白いです。
1 2 |
|
このように、”Priority” というプロパティ名を持つインターフェイスを宣言します。 ちなみに、このインターフェイスはどこも実装はされていません。
このインターフェイスが判断材料用のオブジェクトとして、コンテナによって動的に実態化されます。
以下がサンプルになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
GetExports メソッドの型パラメーター 1 は、取得したい型で、 2つ目の引数は判断材料となるExportMetadata属性 の情報を転送できる 任意のインターフェイスなりクラスとなります。
ここに IPriority インターフェイスを設定すると、コンテナがGUIDを利用して動的クラスを構築、生成し、 そのメンバに属性値を割り当ててくれます。
そのため、その任意の判断材料を利用して複数のクラスからある特定のクラスを返すことができるようになります。
今回は Priority という優先度のサンプルでしたが、たとえばデータベースのサービス名などを文字として 切り分け判断材料に利用すれば、データベース非依存のサービスなどいろいろと応用ができそうです。