かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Managed Extensibility Framework入門 その1「はじめに」

参考情報

入門の最初にいきなり参考情報というのもなんですが、以下のサイトで独学出来る人はこれから書くであろう一連のエントリは見なくてもいいと思います。もし、見て頂けるなら、この解釈間違ってるとか、この記述がおかしいとコメントなどで指摘して頂けるとうれしいです。

開発しているサイト

.NET Framework 4とSilverlight 4からひっそりと?追加されているものの中に、Managed Extensibility Framework(以降MEF)というものがあります。MEFは、CodePlexで開発が行われていて公式サイトは以下になります。

MSDN内のMEFのサイト

また、MSDN内にも概要が書かれています。MSDNの内容も丁寧に書かれているので、ここで書く必要も無いのでは??と思ったりもしましたが、自分の理解のために書いていこうと思います。

この連載の目標

MSDNマガジンの以下の記事を読んで理解できるくらいのレベルになれることを目標にしてます。

この連載の特徴

図がありません。画面のスクリーンショットくらいは載せると思います。

自分なりに解釈したMEFの概要

MSDNの方にも概要がきちんと書いてありますが、私なりに解釈した内容を書いていこうと思います。
MEFは、拡張可能なアプリケーションを作成するための一連の機能を提供するライブラリです。拡張可能なアプリケーションとはどういうことかというと、アドインを使って機能を追加できるタイプのアプリケーションのことを指しています。

代表的なものとしてはExcelやWordなどのOffice製品や開発環境ではVisual StudioEclipse, NetBeansなどの最近メジャーな開発環境は全てアドイン(アドオン、プラグインと呼ぶ環境もあります)を使って機能拡張を行うことができるようになっています。少し横道にそれますが、最近の開発環境はウィンドウの管理や必要最低限のメニューをコアの機能として開発して、その上にアドインする形で開発環境を構築するといった形で作られていたりします。このように、予め拡張をすることを前提に作っていくことで将来の機能拡張にも柔軟に対応できるように作られています。しかも、Visual Studio 2010の拡張機能はMEFベースなのでMEFを勉強しておくとVisual Studioの機能拡張をするときの敷居が下がるというおまけまでついてきます。(Visual Studioを拡張することが現実問題としてあるのかという話もありますが痛IDEとかみたいなアイデアを思いついたときに実現できる基本的なスキルを持っておくのは素敵なことだと個人的には思います。)

少し横道にそれたところでMEFに話を戻します。MEFは、これらの拡張可能なアプリケーションを作ろうとしたときに必要になるであろう機能セットを提供してくれるというわけです。


これで、MEFは拡張可能なアプリケーションを作成するためのフレームワークという一文が理解できるようになると思います。

具体的にどんな機能を提供しているの?

MEFを使うことで、どんなことが実現できるのかということが、なんとなく理解できたところで、MEFが提供している機能について、もう少し具体的に踏み込んで説明していきます。


MEFが提供してる機能を一言でいうとDIコンテナになります。DIコンテナって何?っていう方は"DIコンテナ"や"IoC コンテナ"でGoogle様に聞くといっぱい既存の資料が出てきます。一応Wikipediaにも記事があったりします(正直貧弱ですが)


ここでも、簡単にDIコンテナについて私なりの文章で説明してみようと思います。DIコンテナのDIの部分はDependency Injectionの略称で日本語では依存性の注入と言われたりします。正直この和約で理解できる人は天才だと思ってたりしますが、依存性の注入の依存性の部分が具体的になにを指すのかから説明したいと思います。

依存性とは

ここでいう依存性とは以下のような関係を持つクラスAとクラスBがあったとします。

class A
{
  public void Foo()
  {
    // Bクラスを使ってる
    B b = new B();
    b.Bar();
  }
}

class B
{
  public void Bar() { }
}

上記のようにAクラスがBクラスを使ってる状態のことをAクラスがBクラスに依存していると言うことにします。ここでいってる依存性というのはこういう依存関係のことを言っています。まぁ普通に設計して普通にプログラムを書いたら、複数のクラスが連携して動作をするようになるので、このような依存関係はいたるところにあることになります。

注入とは

では、その依存性を注入するの注入とはどういうことを言うのか説明します。ここで注入というのは、依存関係を外部から設定するということを表します。まだ言葉だけではイメージしにくいので、上記のクラスAとクラスBの依存関係を外部から注入可能なように作り変えてみます。

class A
{
  private B b;
  
  // コンストラクタでBを設定できるようにする
  public A(B b)
  {
    this.b = b;
  }
  
  public void Foo()
  {
    b.Bar();
  }
}

class B
{
  public void Bar() { }
}

では、作り変える前と、作り変えた後でクラスAを使う人が書くであろうコードを書いてみます。

// 変更前の場合
A a = new A();
a.Foo();

// 変更後の場合
B b = new B();
A a = new A(b);
a.Foo();

何が変わったかというと、変更前の状態ではAクラスを使う側は、Aクラスを作るだけでAクラスを作れます。これはAクラス内部でAクラスの依存先のインスタンスを管理してるためです。変更後は、依存先のインスタンスを外部から渡してもらう(注入してもらう)ような形にAクラスがなってるので、使う側でBクラスを準備して、Aクラスが使うインスタンスを指定しています。

このような変更後の状態をAクラスへBクラスを注入しているという風に言っています。普通いいませんよねハイ。私もDIコンテナで依存性の注入という言葉が出てくるまで使ったことありませんでした。

依存性が注入できることのメリット

ということで依存性の注入がどういうものを表すのかわかったと思います。依存性を注入できるように作るとどんなメリットがあるのかというと、Aクラスが使用するBクラスを自由に差し替えが可能だという点があります。具体的にこれがメリットを発揮するのは単体テスト時です。このように依存先のクラスを差し替え可能にすることで、単体テスト時は単体テスト用のインスタンスを、本番時には本番用のインスタンスを差し替えたりといったことがメリットとして一般的に言われています。(実際にはインターフェースを使うことでAとBの依存関係をきれいに分離してBクラスのテスト用実装とかを定義できるようにしたりすることが多いです)

DIコンテナとは

さて、依存性の注入のメリット?が一応わかったとといっても依存性を注入できるように作ったクラスは使うのがメンドクサイというデメリットがあったりします。まぁ、Aクラスを引数ありのコンストラクタと引数なしのコンストラクタを用意して引数なしのコンストラクタが呼ばれた場合はデフォルトの依存先のインスタンスを作るという風にすればデメリットも特に無いように感じるのですが・・・それは置いといて、DIコンテナと呼ばれるものが何をするのかという点を説明したいと思います。


DIコンテナとは、めんどくさいクラス間の依存性の注入を面倒を見てくれるクラスのことです。DIコンテナというクラスがあるとして、上で書いたAクラスを使う部分のコードを以下に示します。

DIコンテナ c = new DIコンテナ():
A a = c.インスタンス取得<A>();
a.Foo();

DIコンテナが、AクラスとBクラスの依存関係を何らかの方法で認識してAクラスを取得するときにBクラスを注入してくれるという仕事をしてくれます。そのため、Aクラスを使う場所ではAクラスのインスタンスが欲しいとDIコンテナにお願いするだけでよくなります。今回は2クラスしかいませんが、クラス数が増えてくるとDIコンテナが依存関係とインスタンスの生成の面倒をみてくれると楽になりそうな気がしますね?

今回のまとめ

ということで長々と書いたので簡単にまとめます。

まだMEFの具体的な所にはさっぱり触れてないのですが今回はここで力尽きました。ということで続く・・・。