簡単に実現することができる仕組みだと認識しています。
以前はプラグインを実行時に読み込むには、
リフレクションを使ってそれなりのコードを書かないといけなかったのですが、
MEFによりだいぶ単純になっていて、また柔軟さを持っているようです。
※使いこなしていないので断言できません
本当はこれまでのように実際のコードで例を示したかったのですが、
複雑になりそうなのでサンプルコードで示します。
まず一つのクラス内でむりやり書いたコードです。
一応twitterクライアントで使えそうなシチュエーションということで、
タイムラインを表すITimelineインターフェイスと、
その具体的な実装PublicTimelineクラスとFriendTimelineクラスがあります。
そしてExport属性を付けたクラスを
ImportまたはImportMany属性を付けたプロパティが受け取ります。
コンストラクタでやっていることは、
CatalogクラスがExportを探してくる役目、
CompositionContainerがExportとImportの参照関係を構築する役目、
といったところです。(たぶん)
using System.ComponentModel.Composition; using System.Reflection; using System.ComponentModel.Composition.Hosting; public partial class MainWindow : Window { public MainWindow() { DataContext = this; var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); InitializeComponent(); } public interface ITimeline { string Name { get; } } [Export(typeof(ITimeline))] class PublicTimeline : ITimeline { public string Name { get { return "みんなのタイムライン"; } } } [Export(typeof(ITimeline))] class FriendTimeline : ITimeline { public string Name { get { return "友達のタイムライン"; } } } [ImportMany] public IEnumerable<ITimeline> AllTimelines { get; set; } }
もちろん実際Exportするのははインナークラスである必要はありません。
ためしにViewを以下のように書いたらタイムライン名が表示されるはずです。
<Window x:Class="MEFSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <ListBox ItemsSource="{Binding Path=AllTimelines}" DisplayMemberPath="Name"/> </Grid> </Window>
使う側(Importする側)でITimelineの実装クラスを列挙する必要がないことに注目してください。
また、タイムラインの実装クラスを増やしたい場合はExportがついたクラスを増やすだけです。
この場合も使う側(Importする側)に変更がいりません。
ただこの方法では、同じアセンブリからしかImportできません。
他のファイル(.dll)からImportするには、DirectoryCatalogを使います。
上のサンプルとは全く関係ありませんが、
作成中のアプリのコードで示すと、
Pluginディレクトリのなかのすべてのdllファイルの中の
IServiceインターフェイスの実装を探すコードは
たとえば以下のような感じになります。
using (var dirCatalog = new DirectoryCatalog("Plugins")) using (var container = new CompositionContainer(dirCatalog)) { _services = container.GetExportedValues<IService>(); }
(1例目はMSDNのサンプルがそうなっていたのでやっていませんでしたが、
Dispose()があるので実際のコードの2例目はusingで囲っています。)
これで、「プラグインはIServiceを実装してPluginディレクトリに入れる」というルールを決めるだけで
アプリケーション側はプラグインの一覧を簡単に探すことができます。
実用にはもっといろいろと決めることがありますが、
基本はこんなところです。
他にもCatalogの種類はあるし、いろんな呼び出し方がありそうなので、
詳しくは仕様を調べてください。
クラスではなくてメソッドをインポートする、などできます。
インポートに条件を付けたりもできます。
たくさんページがありますが、公式では以下のページが比較的わかりやすいかなと思いました。
http://msdn.microsoft.com/ja-jp/magazine/ee291628.aspx
0 件のコメント:
コメントを投稿