Managed Extensibility Framework(MEF)入門 -Export-
2MEFではパーツのパーツ自信のインスタンス、プロパティ(フィールド)、メソッドをコンテナーに対しサービスと言う形でエクスポートする事が出来ます。
コンテナーにパーツ単位で登録するのが一般的です。サンプルコードを元に見ていきましょう。
クラスインスタンスのエクスポート
クラスインスタンスをサービスとしてエクスポートするサンプルです。
C#1 using System;
2 using System.ComponentModel.Composition;
3 using System.ComponentModel.Composition.Hosting;
4
5 namespace ExportClass.CSharp
6 {
7 public class Program
8 {
9 /// <summary>
10 /// コンテナー
11 /// </summary>
12 private CompositionContainer container;
13
14 private Program()
15 {
16 //コンテナーを生成
17 this.container = new CompositionContainer();
18 container.ComposeParts(this);
19 //パーツ管理クラス
20 CompositionBatch batch = new CompositionBatch();
21 //MessageSenderをパーツとして登録
22 batch.AddPart(new MessageSender());
23 //パーツ管理クラスを元にコンテナーを構成
24 this.container.Compose(batch);
25 }
26
27 private void Run()
28 {
29 //コンテナーよりエクスポートしたサービスを取得する。
30 MessageSender messageSender = this.container.GetExportedValue<MessageSender>();
31 Console.WriteLine(messageSender.GetMessage());
32 }
33
34 public static void Main(string[] args)
35 {
36 Program program = new Program();
37 program.Run();
38 }
39 }
40
41 //クラスインスタンスとしてエクスポート
42 [Export]
43 public class MessageSender
44 {
45 public string GetMessage()
46 {
47 return "メッセージです。";
48 }
49 }
50 }
VB1 Imports System
2 Imports System.ComponentModel.Composition
3 Imports System.ComponentModel.Composition.Hosting
4
5 Public Class Program
6 ''' <summary>
7 ''' コンテナー
8 ''' </summary>
9 Private container As CompositionContainer
10
11 Private Sub New()
12 'コンテナーを生成
13 Me.container = New CompositionContainer()
14 'パーツ管理クラスを生成
15 Dim batch As New CompositionBatch()
16 'MessageSenderをパーツとして登録
17 batch.AddPart(New MessageSender())
18 'パーツ管理クラスを元にコンテナーを構成
19 Me.container.Compose(batch)
20 End Sub
21
22 Private Sub Run()
23 'コンテナーよりエクスポートしたサービスを取得する。
24 Dim messageSender As MessageSender = Me.container.GetExportedValue(Of MessageSender)()
25 Console.WriteLine(messageSender.GetMessage())
26 End Sub
27
28 Public Shared Sub Main()
29 Dim program As New Program()
30 program.Run()
31 End Sub
32 End Class
33
34 'クラスインスタンスとしてエクスポート
35 <Export()> _
36 Public Class MessageSender
37 Public Function GetMessage()
38 Return "メッセージです。"
39 End Function
40 End Class
上記はMessageSenderクラスをクラスインスタンスとしてコンテナーにエクスポートしている例です。クラスインスタンスをコンテナーにエクスポートするようにマーキングするには、クラスに属性として『System.ComponentModel.Composition.ExportAttribute』を定義します。サンプルコードではC#(16行目〜23行目)とVB(12行目〜19行目)でコンテナーにMessageSenderインスタンスをサービスとして、MessageSenderクラスをパーツとして登録しています。CompositionContainerクラスやCompositionBatchクラスが登場しておりますが、今後詳細を取り上げますのでそれまではエクスポートする定型文として今は覚えておいて下さい。登録後のサービスをC#(29行目)とVB(24行目)で取得し使用しています。サンプルコードではMessageSenderクラスのインスタンスを明示的に生成しており、冗長なファクトリークラスを定義しているようにしかなっておりません。DIコンテナーのメリットの「インターフェースと実装の分離」が行われておりませんので、MessageSenderクラスを実装クラスとし、新たにIMessageSenderインターフェースを作成したサンプルを見てみましょう。
C#1 using System;
2 using System.ComponentModel.Composition;
3 using System.ComponentModel.Composition.Hosting;
4
5 namespace ExportClass.CSharp
6 {
7 public class Program
8 {
9 /// <summary>
10 /// コンテナー
11 /// </summary>
12 private CompositionContainer container;
13
14 private Program()
15 {
16 //コンテナーを生成
17 this.container = new CompositionContainer();
18 container.ComposeParts(this);
19 //パーツ管理クラス
20 CompositionBatch batch = new CompositionBatch();
21 //MessageSenderをパーツとして登録
22 batch.AddPart(new MessageSender());
23 //パーツ管理クラスを元にコンテナーを構成
24 this.container.Compose(batch);
25 }
26
27 private void Run()
28 {
29 //コンテナーよりエクスポートしたサービスを取得する。
30 IMessageSender messageSender = this.container.GetExportedValue<IMessageSender>();
31 Console.WriteLine(messageSender.GetMessage());
32 }
33
34 public static void Main(string[] args)
35 {
36 Program program = new Program();
37 program.Run();
38 }
39 }
40
41 public interface IMessageSender
42 {
43 string GetMessage();
44 }
45
46 //IMessageSender型としてエクスポート
47 [Export(typeof(IMessageSender))]
48 public class MessageSender : IMessageSender
49 {
50 public string GetMessage()
51 {
52 return "メッセージです。";
53 }
54 }
55 }
VB1 Imports System
2 Imports System.ComponentModel.Composition
3 Imports System.ComponentModel.Composition.Hosting
4
5 Public Class Program
6 ''' <summary>
7 ''' コンテナー
8 ''' </summary>
9 Private container As CompositionContainer
10
11 Private Sub New()
12 'コン テナーを生成
13 Me.container = New CompositionContainer()
14 'パーツ管理クラスを生成
15 Dim batch As New CompositionBatch()
16 'MessageSenderdをパーツとして登録
17 batch.AddPart(New MessageSender())
18 'パーツ管理クラスを元にコンテナーを構成
19 Me.container.Compose(batch)
20 End Sub
21
22 Private Sub Run()
23 'コンテナーよりエクスポートしたサービスを取得する。
24 Dim messageSender As IMessageSender = Me.container.GetExportedValue(Of IMessageSender)()
25 Console.WriteLine(messageSender.GetMessage())
26 End Sub
27
28 Public Shared Sub Main()
29 Dim program As New Program()
30 program.Run()
31 End Sub
32 End Class
33
34 Public Interface IMessageSender
35 Function GetMessage() As String
36 End Interface
37
38 'IMessageSender型としてエクスポート
39 <Export(GetType(IMessageSender))> _
40 Public Class MessageSender
41 Implements IMessageSender
42 Public Function GetMessage() As String Implements IMessageSender.GetMessage
43 Return "メッセージです。"
44 End Function
45 End Class
このようにインターフェース型への実装の注入が簡単に行える事が分かります。現在はコンテナーより直接エクスポートしたサービスを取得していますが、次回取り上げる「インポート」と併用する事で利便性が格段に向上します。