プラグイン機構

MoNo.RAIL におけるプラグインとは

主に次の2つの用途でプラグイン機構が利用されます。

  • あるエンティティを描画するためのシーンオブジェクト生成のプラグイン
  • あるエンティティをファイル保存(シリアライズ)するためのシリアライザのプラグイン

何らかのエンティティは、それがどのように描画されるか、あるいはどのようにシリアライズされるか、といった実装とは無関係に定義されるべきです。 エンティティの定義はそのエンティティの本質を簡潔に捉えたデータ表現に留めるべきであり、描画処理やシリアライズ処理といった雑多な関心事が混在するべきではありません。 これは「関心の分離」というソフトウェア設計の原則に照らして重要です。

そこで、エンティティクラスとは別のクラスとして描画を担うシーンクラスやシリアライズを担うシリアライザクラスを実装するようにします。 しかし、それだけではエンティティからシーンやシリアライザを結びつけることが出来ません。 フレームワーク(MoNo.RAIL)にエンティティを渡したとき、そのエンティティから対応するシーンやシリアライザを生成できるように関連付けておく必要があります。

その関連付けの手段として、ここで説明するプラグインの機構が利用されています。

MEF

.NET Framework には MEF(Managed Extensibility Framework) と呼ばれるプラグイン機構が備わっています。 MoNo.RAIL は基本的には MEF をシンプルに素直に利用しているだけです。

MEF についてはここでは説明しません。MSDN等の資料に当たって下さい。

プラグインの書き方

参照設定に System.ComponentModel.Composition.dll を追加し、次のように書きます。

open System.ComponentModel.Composition

[<Export (typeof<MoNo.Graphics.ISceneFactory>)>]
type FooSceneFactory () = ...

[<Export (typeof<MoNo.IO.ISerializer>)>]
type BuzzSerializer () = ...

このように、クラスに System.ComponentModel.Composition.Export 属性を付けておくだけでプラグインと認識され、フレームワーク側に登録されます。

ただし、これらプラグインクラスが含まれたアセンブリ(DLL/EXE)は、実行ファイルと同じフォルダに入っている必要があります。 これを変更したい場合(例えば特定フォルダに含まれているアセンブリのみをプラグインとしたい場合など)は、次で説明する PluginContainer を変更します。

PluginContainer

MoNo.Basics.dll には PluginContainer というものが次のように定義されています。

using System.ComponentModel.Composition.Hosting;

namespace MoNo
{
  public static partial class CoreUT
  {
    static CompositionContainer _plugins = new CompositionContainer(
      new AggregateCatalog(
        new DirectoryCatalog( ".", "*.exe" ),
        new DirectoryCatalog( ".", "*.dll" ) ) );

    public static CompositionContainer PluginContainer
    {
      get { return _plugins; }
      set { _plugins = value; }
    }

        ...
  }
}

これを使って、次のようなコードでプラグインされたオブジェクトを取得することが出来ます。

// プラグインされたシーンファクトリの取得
MoNo.CoreUT.PluginContainer.GetExports<MoNo.Graphics.ISceneFactory>();

// プラグインされたシリアライザの取得
MoNo.CoreUT.PluginContainer.GetExports<MoNo.IO.ISerializer>();

PluginContainer プロパティは setter も定義されています。 つまり PluginContainer を別のものに変更することが可能です。

デフォルトでは「実行モジュールと同じフォルダにあるアセンブリをプラグインの対象とする」という設定になっていますが、必要に応じて異なる設定に変更することが出来ます。