MEFによるC#アドインの作成

.NET Framework4.0で登場したMEFによりアドイン作成が非常に簡単になりました。

MEFを使ったアドイン構成方法を紹介します。

大まかな手順は、

  1. アドインのIFを決める
  2. 参照されるアドインを作成する
  3. アドインをロードする側を作成する

となります。

準備としてまず以下の4つのプロジェクトを作成しておきます。AddinContractはアドイン提供機能を定義する抽象層、

AddinA, AddinBはアドインを実装する外部プロジェクトの想定、UseAddinFormはWinFormsのアドイン受付モジュールです。

image1

Step1.アドインのIFを決める

クラス設計原則SOLIDの、DIPでも言われるようアドインを提供する側、アドインを作成する側、ともに抽象に依存するため、

アドインが提供する機能 (=アドインで提供される機能)をC#のInterfaceとして作成します。

AddinContract.proj

namespace AddinContract{
     public interface IAddinContract{
          string AddinTitle { get; }
          void DoWork();
     }
}

単にアドインの名前と処理を返すことにします。

Step2.アドインで提供する機能を実装する

AddinA.proj

using System.ComponentModel.Composition;
namespace AddinA {
     [Export(typeof(IAddinContract))]
     public class AddinSampleA : IAddinContract     {
          public string AddinTitle { get { return "Addin - A"; } }
          public void DoWork(){return;}
     }
}

ポイントはExport(typeof(IAddinContract))属性です。MEFにここからAddinをExportしますよ~と伝えます。
これで1つのアドインができました。他のアドインを作る場合も同様にExportで機能公開し、
ちゃんとIAddinContractを実装します。

Step3.アドインをロード、実行する

見た目はこんな感じ。

form

WinFormsである必要はないのですが、わかりやすい例としてこれにしました。

 

UseAddinForm.proj

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace UseAddinForm {
     public partial class ExtensibleForm : Form     {

          [ImportMany]
          private List addins;

          public ExtensibleForm(){
               InitializeComponent();
          }

          public void UpdateAddins() {
               try{
                    var container = GetContainerFromDirectory();
                    container.ComposeParts(this);
               }
               catch (CompositionException){
                    // through.
               }
          }

          private CompositionContainer GetContainerFromDirectory(){
               var catalog = new DirectoryCatalog("addins");
               return new CompositionContainer(catalog);
          }

          private void updateButton_Click(object sender, EventArgs e){
               UpdateAddins();
               foreach (var addin in addins){
                    addinsListBox.Items.Add(addin.AddinTitle);
               }
          }

          private void executeButton_Click(object sender, EventArgs e){
               if (addinsListBox.SelectedIndex < 0){
                    return;
               }
               addins[addinsListBox.SelectedIndex].DoWork();
          }

          private void closeButton_Click(object sender, EventArgs e){
               Close();
          }
     }
}

想定として、実行プログラムの下にaddinsサブフォルダがあり、その中にアドインを実装したdllがある想定です。

ここでのポイントはImportManyでアドインを保持する構造を作っておくことでしょうか。
アドインを使う側の上記コードではどこにもaddinsにデータをセットする人がいません。

にもかかわらず、実行ボタンを押下するとアドインの一覧が表示されます。

adin実行の様子

ここでは単機能のアドインですが、アドイン側で新たにFormを立ち上げたり、サービスを立ち上げたりできます。

商利用のアドインでは、ユーザが追加購入して「画像処理モジュール」や「信号解析モジュール」を

追加搭載する、といった形のものが一般的かと思います。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中