JUGEMテーマ:
コンピュータ
Source and Project※当Blogの最近のMEFの投稿はMEFフレームワークを必ずしも正しい使い方をしているとは限りませんので注意してください。
ComposablePartCatalog クラス、ComposablePartDefinition クラス、ComposablePart クラスを使用して自作カタログを作成しました。クラスのそれぞれの責務はMSDNライブラリーによると
-------------------
ComposablePartCatalog クラス
ComposablePartDefinition オブジェクトを収集して返すコンポーザブル パーツ カタログの抽象基本クラスを表します。
ComposablePartDefinition クラス
ComposablePart オブジェクトの作成を記述して有効にするコンポーザブル パーツ定義の抽象基本クラスを定義します。
ComposablePart クラス
オブジェクトをインポートしたり、エクスポートされたオブジェクトを生成したりするコンポーザブル パーツの抽象基本クラスを定義します。
--------------------
カタログを自作したり拡張したい場合にすべてをこれらの抽象クラスから直接継承する必要は全くないと思いますが、これらの抽象クラスのメンバーがいつ呼ばれるのかシーケンスが知りたいのと、属性付きプログラミング モデル以外でも実装可能なことを試してみたいなど、いろいろやってみたいことがあったので、実装してみました。
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
namespace Art55.MEF.JunkLib
{
public class MyComposablePartCatalog : ComposablePartCatalog
{
public MyComposablePartCatalog(params Type[] types)
{
_partDefinitionList = new List<ComposablePartDefinition>();
foreach (Type type in types)
{
_partDefinitionList.Add(new MyComposablePartDefinition(type));
}
}
public override IQueryable<ComposablePartDefinition> Parts
{
get { return _partDefinitionList.AsQueryable(); }
}
private readonly List<ComposablePartDefinition> _partDefinitionList;
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Reflection;
namespace Art55.MEF.JunkLib
{
class MyComposablePartDefinition : ComposablePartDefinition
{
public MyComposablePartDefinition(Type type)
{
_type = type;
var metadata = new Dictionary<string, object>();
metadata[CompositionConstants.ExportTypeIdentityMetadataName] =
AttributedModelServices.GetTypeIdentity(type);
_rootExportDefinition = new ExportDefinition(AttributedModelServices.GetContractName(type), metadata);
_exportDefinitionList = new List<ExportDefinition> { _rootExportDefinition };
_importDefinitionList = new Dictionary<ImportDefinition, PropertyInfo>();
foreach (PropertyInfo propertyInfo in type.GetProperties())
{
if (propertyInfo.CanWrite)
{
Type importType = propertyInfo.PropertyType;
var importDefinition = new ContractBasedImportDefinition(
AttributedModelServices.GetContractName(importType),
AttributedModelServices.GetTypeIdentity(importType),
Enumerable.Empty<KeyValuePair<string, Type>>(),
ImportCardinality.ExactlyOne,
false,
false,
CreationPolicy.Shared);
_importDefinitionList.Add(importDefinition, propertyInfo);
}
}
}
public override IEnumerable<ExportDefinition> ExportDefinitions
{
get { return _exportDefinitionList; }
}
public override IEnumerable<ImportDefinition> ImportDefinitions
{
get { return _importDefinitionList.Keys; }
}
public override ComposablePart CreatePart()
{
return new MyComposablePart(this);
}
public Export CreateExport()
{
return new Export(_rootExportDefinition, () => Activator.CreateInstance(_type));
}
internal void SetImport(object obj, ImportDefinition importDefinition, Export export)
{
if (_importDefinitionList.ContainsKey(importDefinition))
{
PropertyInfo propertyInfo = _importDefinitionList[importDefinition];
propertyInfo.SetValue(obj, export.Value, null);
}
}
private readonly Type _type;
private readonly ExportDefinition _rootExportDefinition;
private readonly List<ExportDefinition> _exportDefinitionList;
private readonly Dictionary<ImportDefinition, PropertyInfo> _importDefinitionList;
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
namespace Art55.MEF.JunkLib
{
class MyComposablePart : ComposablePart
{
public MyComposablePart(MyComposablePartDefinition definition)
{
if (definition == null)
throw new ArgumentNullException("definition");
_definition = definition;
}
public override IEnumerable<ExportDefinition> ExportDefinitions
{
get { return _definition.ExportDefinitions; }
}
public override IEnumerable<ImportDefinition> ImportDefinitions
{
get { return _definition.ImportDefinitions; }
}
public override object GetExportedValue(ExportDefinition definition)
{
if (_definition.Equals(definition))
throw new ArgumentException("definition");
object result = _definition.CreateExport().Value;
foreach (ImportDefinition importDefinition in _importSetting.Keys)
{
if (_importSetting.ContainsKey(importDefinition) && _importSetting[importDefinition].Count() == 1)
{
_definition.SetImport(result, importDefinition, _importSetting[importDefinition].First());
}
}
return result;
}
public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
{
_importSetting[definition] = exports;
}
private readonly Dictionary<ImportDefinition, IEnumerable<Export>> _importSetting = new Dictionary<ImportDefinition, IEnumerable<Export>>();
private readonly MyComposablePartDefinition _definition;
}
}
これらのクラスを使用してカタログを作成すると
指定したTypeは必ずExportとなり、publicなGetterが存在するプロパティは必ずImportとして設定されます。そして、Exportからインスタンスを作成時にインジェクションされます。実際のライブラリーを使用してインスタンスを作成するコードを書いてみると
using System;
using System.ComponentModel.Composition.Hosting;
using Art55.MEF.JunkLib;
namespace Art55.MEFSample20100525_001
{
class Program
{
static void Main(string[] args)
{
var types = new[] {typeof (B), typeof (A), typeof (C)};
var catalog = new MyComposablePartCatalog(types);
var container = new CompositionContainer(catalog);
A a = container.GetExportedValue<A>();
a.Say();
}
}
public class A
{
public B BObject { private get; set; }
public void Say()
{
BObject.Say();
}
}
public class B
{
public C CObject { private get; set; }
public void Say()
{
CObject.Say();
}
}
public class C
{
public void Say()
{
Console.WriteLine("C Say");
}
}
}
実行すると
C Say
と出力されます。一応、属性指定なしにExportやImportが指定可能なカタログが作成できました。
Source and Project