MEFでオープンジェネリック型をエクスポート
MefContribにはジェネリック用のGenericCatalogクラスがあります。これを使うとオープンジェネリック型をエクスポートすることができます。ただ、ドキュメント不足な上に、ちょっと癖がありそうです。
公開するインタフェースは、こんな感じです。
// このインタフェースから継承したクラスはすべてエクスポートされる [InheritedExport] public interface ICalc<T> { T Add(T x, T y); T Div(T x, T y); }
色々試した限りでは、実装クラスにExport属性を付けてもうまくいかず、インタフェースにInheritedExport属性を付ける必要がありました。とりあえず、オープンジェネリック型をエクスポートする場合は、インタフェースにInheritedExport属性を付けましょう。
実装は適当に。
// このエクスポートは発見されない。 // ネット上のサンプルを見る限り、できそうなんだけど・・・ // [Export(typeof(ICalc<>))] public class CalcImpl<T> : ICalc<T> { public T Add(T x, T y) { return (dynamic)x + y; } public T Div(T x, T y) { return (dynamic)x / y; } }
テストなのでdynamicを使ってごまかしておきます。
次にジェネリックインタフェースと実装クラスのマッピングを定義するクラスを用意します。GenericCatalogにこのクラスを渡すことで型を解決できるようになるようです。
/// <summary> /// open genericの場合、実装クラスとのマッピングを指定する必要がある。 /// </summary> [Export(typeof(IGenericContractRegistry))] public class MyGenericContractRegistry : GenericContractRegistryBase { protected override void Initialize() { Register(typeof(ICalc<>), typeof(CalcImpl<>)); } }
準備ができたので、さっそく使ってみましょう。
[Export]
class Program
{
[Import]
public ICalc<int> CalcInt32 { get; set; }
[Import]
public ICalc<double> CalcDouble { get; set; }
public void Run()
{
int x = 1, y = 2;
Console.WriteLine("{0} / {1} = {2}", x, y, CalcInt32.Div(x, y));
Console.WriteLine("{0} / {1} = {2}", x, y, CalcDouble.Div(x, y));
}
static void Main(string[] args)
{
var catalog = new TypeCatalog(typeof (Program));
var generic = new GenericCatalog(catalog, new MyGenericContractRegistry());
var container = new CompositionContainer(generic);
var program = container.GetExportedValue<Program>();
program.Run();
}
}
/* 結果
1 / 2 = 0
1 / 2 = 0.5
*/
CodePlexのフォーラムやブログにあったサンプルが今のMefContribだと動かないので試行錯誤になりましたが、多分、こんな感じ。(^^;