MEFによる動的な機能追加

さらにもう1つ、実行時に動的に機能を変更する例を見てみよう。MEFでは、処理を行う際に使用するクラスを簡単に切り替えることができることを確認できる(サンプルコードをこちらからダウンロードできる)。

今回は3つのプロジェクトを作成する。MEFComponent1プロジェクトとMEFComponent2プロジェクトは、実装が異なる2つのコンポーネントを用意するためのプロジェクトだ。そしてMEFSample2プロジェクトが、この2つのコンポーネントを切り替えて使用するためのプロジェクトとなっている。

まず、MEFSample2プロジェクトの方で、インタフェースを用意する。今回のサンプルでは文字列をやりとりするので、次のようなインタフェースを定義した。

public interface IMessageManager
{
    string GetMessage(string name);
}

次に、このIMessageManagerインタフェースを実装したクラスを定義する。

まずMEFComponent1プロジェクトに、EnglishMessageManagerクラスを定義しよう。このクラスはIMessageManagerインタフェースを実装するので、MEFSample2プロジェクトへの参照を追加しておく必要がある。

また、MEFのコンポーネントとして使用できるようにするため、Export属性を追加しておく。Export属性を使用するために、System.ComponentModel.Compositionへの参照を追加し、System.ComponentModel.Composition名前空間をインポートしてから、次のソースコードを記述する。

[Export(typeof(IMessageManager))]
class EnglishMessageManager : IMessageManager
{
    public string GetMessage(string name)
    {
        return "こんにちは," + name + "!";
    }
}

続いて、MEFComponent2プロジェクトに、JapaneseMessageManagerクラスを定義する。メッセージが日本語になっていること以外は、EnglishMessageManagerクラスをほぼ同じソースコードになっている。

[Export(typeof(IMessageManager))]
class JapaneseMessageManager  : IMessageManager
{
    public string GetMessage(string name)
    {
        return "こんにちは," + name + "!";
    }
}

最後にMEFSample2プロジェクトで、IMessageManagerインタフェースのインスタンスを生成し、使用する処理を記述しよう。ソースコードは次のようになる。

private void button1_Click(object sender, EventArgs e)
{
    //exeファイルが存在するディレクトリにあるアセンブリを使用して、コンテナを生成する
    var d_catalog = new DirectoryCatalog(".");
    var container = new CompositionContainer(d_catalog);

    IMessageManager ims = container.GetExportedObject<IMessageManager>();
    MessageBox.Show(ims.GetMessage("MEF"));
}

MEFSample1と異なり、今度は実行ファイル自身のアセンブリではなく、実行ファイルが存在するディレクトリにあるアセンブリに含まれるクラスを使用することになる。そこで、指定されたディレクトリにあるアセンブリを使用する「DirectoryCatalog」クラスを使用して、コンテナを生成するような処理を行っている。

以上で、今回のサンプルは完成である。ビルドして実行した後、まずMEFComponent1.dllをMEFSample2.exeと同じフォルダに移動し、フォームのボタンをクリックしてみよう。すると「Hello,MEF!」というメッセージが表示されることを確認できる。

次に、MEFSample2.exeは起動したままで、MEFComponent1.dllを元のフォルダに戻した後、MEFComponent2.dllをMEFSample2.exeと同じフォルダに移動し、フォームのボタンをクリックしてみよう。すると「こんにちは、MEF!」というメッセージが表示されることを確認できる。

このように、プログラムを実行中であっても、動的にコンポーネントの切り替えができるのだ。まさにMEFが「Extensibility」を実現するためのフレームワークであることがお分かりいただけたと思う。

MEFはまだプレビュー版であるため、これからもさまざまな変更が行われる可能性はあるが、MEFによってどのような仕組みが実現できるかはご理解いただけただろう。今回は紹介できなかったが、Import属性や便利なカタログクラスなど、他にもさまざまな機能があるため、ぜひ一度MEFのWebサイトにも目を通してみていただきたい。