Managed Extensibility Framework(MEF)入門 -AssemblyCatalog-
MEFではコンテナーにある領域のパーツを取り込む為の機構として「カタログ」と言う物が用意されています。今回は「アセンブリ内のパーツを取り込む」為のカタログ『System.ComponentModel.Composition.Hosting.AssemblyCatalog』クラスを取り上げます。AssemblyCatalogクラスはMSDNでこのように説明されています。
AssemblyCatalog は、指定されたアセンブリ内にあるすべてのパーツを解析するために使用されます。ターゲット アセンブリは、オブジェクト参照またはパスによって示すことができます
AssemblyCatalogはコンストラクタで指定されたパス、又はオブジェクト参照を元に指定アセンブリよりパーツを検出します。そのAssemblyCatalogクラスをコンテナーのコンストラクタ引数に設定するとコンテナーはカタログよりパーツを取得しコンテナー内に構成します。
簡単なサンプルコードを元に見てみましょう。
C#
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace AssemblyCatalogSample.CSharp
{
public class Program
{
/// <summary>
/// コンテナ
/// </summary>
private CompositionContainer container;
/// <summary>
/// View群
/// </summary>
[ImportMany()]
public IEnumerable<IView> Views { get; set; }
/// <summary>
/// コンストラクタ
/// </summary>
private Program()
{
//Programクラスが格納されているアセンブリよりパーツを検出する。
AssemblyCatalog catalog = new AssemblyCatalog(typeof(Program).Assembly);
//指定カタログを用いてコンテナがパーツを検出する。
this.container = new CompositionContainer(catalog);
}
/// <summary>
/// 処理実行
/// </summary>
private void Run()
{
//コンテナより直接サービスを取得する。
IEnumerable<IView> views = this.container.GetExportedValues<IView>();
foreach (IView view in views)
{
Console.WriteLine(string.Format("タイトルは[{0}]です。", view.GetTitle()));
}
//自分のインスタンスにサービスをインポートして貰う。
this.container.ComposeParts(this);
foreach (IView view in this.Views)
{
Console.WriteLine(string.Format("タイトルは[{0}]です。", view.GetTitle()));
}
}
/// <summary>
/// エントリポイント
/// </summary>
public static void Main()
{
Program program = new Program();
program.Run();
}
}
/// <summary>
/// IViewインターフェース
/// </summary>
public interface IView
{
/// <summary>
/// タイトル取得
/// </summary>
string GetTitle();
}
/// <summary>
/// メインビュー
/// </summary>
[Export(typeof(IView))]
public class MainView : IView
{
public string GetTitle()
{
return "Main Window";
}
}
/// <summary>
/// メッセージダイアログ
/// </summary>
[Export(typeof(IView))]
public class MessageDialog : IView
{
public string GetTitle()
{
return "Message Dialog";
}
}
}
VB
Imports System
Imports System.ComponentModel.Composition
Imports System.ComponentModel.Composition.Hosting
Public Class Program
''' <summary>
''' コンテナー
''' </summary>
Private container As CompositionContainer
''' <summary>
''' View群
''' </summary>
<ImportMany()> _
Public Property Views() As IEnumerable(Of IView)
''' <summary>
''' エントリポイント
''' </summary>
Public Shared Sub Main()
Dim program As New Program()
program.Run()
End Sub
''' <summary>
''' コンストラクタ
''' </summary>
Private Sub New()
'Programクラスが格納されているアセンブリよりパーツを検出する。
Dim catalog As New AssemblyCatalog(GetType(Program).Assembly)
'指定カタログを用いてコンテナがパーツを検出する。
Me.container = New CompositionContainer(catalog)
End Sub
''' <summary>
''' 処理実行
''' </summary>
''' <remarks></remarks>
Private Sub Run()
'コンテナより直接サービスを取得する。
Dim views As IEnumerable(Of IView) = Me.container.GetExportedValues(Of IView)()
For Each view As IView In views
Console.WriteLine(String.Format("タイトルは[{0}]です。", view.GetTitle()))
Next
'自分のインスタンスにサービスをインポートして貰う。
Me.container.ComposeParts(Me)
For Each view As IView In Me.Views
Console.WriteLine(String.Format("タイトルは[{0}]です。", view.GetTitle()))
Next
End Sub
End Class
''' <summary>
''' IViewインターフェース
''' </summary>
Public Interface IView
''' <summary>
''' タイトル取得
''' </summary>
Function GetTitle() As String
End Interface
''' <summary>
''' メインビュー
''' </summary>
<Export(GetType(IView))> _
Public Class MainView
Implements IView
''' <summary>
''' タイトル取得
''' </summary>
Public Function GetTitle() As String Implements IView.GetTitle
Return "Main View"
End Function
End Class
''' <summary>
''' メッセージダイアログ
''' </summary>
<Export(GetType(IView))> _
Public Class MessageDialog
Implements IView
''' <summary>
''' タイトル取得
''' </summary>
Public Function GetTitle() As String Implements IView.GetTitle
Return "Message Dialog"
End Function
End Class
サンプルコードを実行すると以下のように出力されます。
サンプルコードでは、Programクラスが格納されているアセンブリ内のパーツ群をAssemblyCatalogクラスを使用してコンテナーに取り込んでいます。今まで取り上げてきた記事では『System.ComponentModel.Composition.Hosting.CompositionBatch』クラスを使用してパーツをCompositionBatchクラスに追加していました。それではアプリケーションで使用するパーツ群を構成する為には一つずつ追加しなけらばならず、効果的とは言えません。カタログを使用する事によってある領域のパーツを取り込む事が出来ます。サンプルコードから分かるようにAssemblyCatalogクラスを使用すると、指定したアセンブリからパーツ群を検出して取り込む事が出来ます。MEFでは一般的にカタログを使用してパーツをコンテナーに取り込みます。「System.ComponentModel.Composition.Hosting」名前空間には様々なカタログが用意されていますので、用途に合わせてカタログを使い柔軟なパーツ構成を行えます。是非試してみては如何でしょうか。