[C#][MEF]Managed Extensibility Framework入門 その1
ということで、MEF Preview 5を試してみます。
プログラムを始めるときは、何事もHello worldからです!!ということで、MEFでも慣例に沿ってHello worldを作っていこうと思います。
プロジェクトの作成~下準備
ということで、早速コンソールアプリケーションを「MEFHelloWorldApp」という名前で新規作成します。MEF Preview 5を解凍したフォルダの下のbinにあるSystem.ComponentModel.Composition.dllを参照に追加します。
プロジェクトを作成したら、最初に、MEFのコンテナの初期化を行います。
とりあえずソースの上にusing(VBならImports)に
- System.ComponentModel.Composition
- System.ComponentModel.Composition.Hosting
の2つを追加します。
C#
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFHelloWorldApp
{
class Program
{
static void Main(string[] args)
{
}
}
}
VB
Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Module Module1
Sub Main()
End Sub
End Module
そしてMainにコンテナの初期化コードを書いていきます。
C#
// コンテナのインスタンスを生成
var container = new CompositionContainer();
// これにコンテナに登録するクラスを指定する
var batch = new CompositionBatch();
// ここでコンテナに登録するクラスを指定する
container.Compose(batch);
// 好きな処理を書く
VB
' コンテナのインスタンスを生成
Dim container As New CompositionContainer
' これにコンテナに登録するクラスを指定する
Dim batch As New CompositionBatch
' ここでコンテナに登録するクラスを指定する
container.Compose(batch)
' 好きな処理を書く
これで下準備完了です。
Hello worldの作成
ここまでは、どのプログラムでも共通する処理です。ここからついにHello worldを作りこんでいきます。
作るクラスとしては、Hello worldという文字列を返すGreeterと、それを標準出力へ印字するGreetApplicationの2つのクラスを作ります。これは、説明もいらない程簡単なクラスなのでさくっとコードを載せます。
C#
using System;
namespace MEFHelloWorldApp
{
public class Greeter
{
public string Greet()
{
return "Hello world";
}
}
public class GreetApplication
{
public Greeter Greeter { get; set; }
public void Run()
{
Console.WriteLine(this.Greeter.Greet());
}
}
}
VB
Public Class Greeter
Public Function Greet() As String
Return "Hello world"
End Function
End Class
Public Class GreetApplication
Private _greeter As Greeter
Public Property Greeter() As Greeter
Get
Return _greeter
End Get
Set(ByVal value As Greeter)
_greeter = value
End Set
End Property
Public Sub Run()
Console.WriteLine(Me.Greeter.Greet())
End Sub
End Class
ここからMEF固有のことをやります。
まず、今回のアプリケーションの形は、GreetApplicationが、Greeterを使うという形になります。そのため、GreetApplicationではGreeterクラスを取得できないといけません。逆にGreeterクラスは、他のクラスに自分を使ってもらえないといけません。
そういうのを表すために属性を追加します。追加する属性は2つで
- System.ComponentModel.Composition.ExportAttribute
自分を外部の人が使えるようにする。
- System.ComponentModel.Composition.ImportAttribute
外部の人を取り込む。
です。
ということで、今回はGreeterクラスにExport属性をつけて、GreetApplicationのGreeterプロパティにImport属性をつけます。
C#
using System;
using System.ComponentModel.Composition;
namespace MEFHelloWorldApp
{
[Export]
public class Greeter
{
public string Greet()
{
return "Hello world";
}
}
public class GreetApplication
{
[Import]
public Greeter Greeter { get; set; }
public void Run()
{
Console.WriteLine(this.Greeter.Greet());
}
}
}
VB
Imports System.ComponentModel.Composition
<Export()> _
Public Class Greeter
Public Function Greet() As String
Return "Hello world"
End Function
End Class
Public Class GreetApplication
Private _greeter As Greeter
<Import()> _
Public Property Greeter() As Greeter
Get
Return _greeter
End Get
Set(ByVal value As Greeter)
_greeter = value
End Set
End Property
Public Sub Run()
Console.WriteLine(Me.Greeter.Greet())
End Sub
End Class
コンテナにクラスを登録して使う
粒がそろったので、MEFのコンテナに登録して使ってみようと思います。
CompositionBatchのAddPart(object)メソッドを使ってインスタンスを登録します。
C#
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFHelloWorldApp
{
class Program
{
static void Main(string[] args)
{
// コンテナのインスタンスを生成
var container = new CompositionContainer();
// これにコンテナに登録するクラスを指定する
var batch = new CompositionBatch();
// ここでコンテナに登録するクラスを指定する
// GreeterとGreetApplicationを追加する
batch.AddPart(new Greeter());
var app = new GreetApplication();
batch.AddPart(app);
container.Compose(batch);
// 好きな処理を書く
app.Run(); // Hello world!!
}
}
}
VB
Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Module Module1
Sub Main()
' コンテナのインスタンスを生成
Dim container As New CompositionContainer
' これにコンテナに登録するクラスを指定する
Dim batch As New CompositionBatch
' ここでコンテナに登録するクラスを指定する
' GreeterとGreetApplicationを追加する
batch.AddPart(New Greeter())
Dim app As New GreetApplication
batch.AddPart(app)
container.Compose(batch)
' 好きな処理を書く
app.Run()
End Sub
End Module
これで、コンテナにGreeterクラスのインスタンスとGreetApplicationクラスのインスタンスを登録してGreetApplicationのRunを実行してます。恐らくcontainer.Compose(batch)の時点で、Export属性やImport属性を見て適切にコンテナが依存性を解決してくれてると思われます。
証拠にこのアプリケーションを実行すると、GreetApplicationのGreeterプロパティに値を設定してるコードが無いにもかかわらず、Hello worldが表示されます。
ということでMEFのHello worldでした。
今回の方法だと、コンテナに登録するインスタンスを全て事前に作っておかないといけないのか!?って感じですけど、ちゃんとフル機能使えば、アセンブリにある属性のついたクラス全部を対象にしたり、フォルダに入ってるアセンブリから読み込んだり夢広がる設計になっています。
ということで、今日はここまで!続きもやるかも・・・?(C#とVB両方用意するの疲れた)