多くの調査の結果、MEF では構成プロセスをインスタンス化プロセスから分離することはできないように思われるため、この問題に対する独自のアプローチを作成する必要がありました。このソリューションでは、プラグインのスキャンによって、タイプ、インポート、およびエクスポートのデータが何らかの方法で保存されることを前提としています。
パーツを構成するには、各パーツ インスタンスと、それが他のパーツ インスタンスにどのように接続されているかを追跡する必要があります。これを行う最も簡単な方法は、どのインポートがどのエクスポートに接続されているかを追跡するグラフ データ構造を利用することです。
public sealed class CompositionCollection
{
private readonly Dictionary<PartId, PartDefinition> m_Parts;
private readonly Graph<PartId, PartEdge> m_PartConnections;
public PartId Add(PartDefinition definition)
{
var id = new PartId();
m_Parts.Add(id, definition);
m_PartConnections.AddVertex(id);
return id;
}
public void Connect(
PartId importingPart,
MyImportDefinition import,
PartId exportingPart,
MyExportDefinition export)
{
// Assume that edges point from the export to the import
m_PartConnections.AddEdge(
new PartEdge(
exportingPart,
export,
importingPart,
import));
}
}
2 つのパーツを接続する前に、インポートをエクスポートに接続できるかどうかを確認する必要があることに注意してください。それ以外の場合は MEF が行いますが、この場合は自分で行う必要があります。そのアプローチ方法の例は次のとおりです。
public bool Accepts(
MyImportDefinition importDefinition,
MyExportDefinition exportDefinition)
{
if (!string.Equals(
importDefinition.ContractName,
exportDefinition.ContractName,
StringComparison.OrdinalIgnoreCase))
{
return false;
}
// Determine what the actual type is we're importing. MEF provides us with
// that information through the RequiredTypeIdentity property. We'll
// get the type identity first (e.g. System.String)
var importRequiredType = importDefinition.RequiredTypeIdentity;
// Once we have the type identity we need to get the type information
// (still in serialized format of course)
var importRequiredTypeDef =
m_Repository.TypeByIdentity(importRequiredType);
// Now find the type we're exporting
var exportType = ExportedType(exportDefinition);
if (AvailableTypeMatchesRequiredType(importRequiredType, exportType))
{
return true;
}
// The import and export can't directly be mapped so maybe the import is a
// special case. Try those
Func<TypeIdentity, TypeDefinition> toDefinition =
t => m_Repository.TypeByIdentity(t);
if (ImportIsCollection(importRequiredTypeDef, toDefinition)
&& ExportMatchesCollectionImport(
importRequiredType,
exportType,
toDefinition))
{
return true;
}
if (ImportIsLazy(importRequiredTypeDef, toDefinition)
&& ExportMatchesLazyImport(importRequiredType, exportType))
{
return true;
}
if (ImportIsFunc(importRequiredTypeDef, toDefinition)
&& ExportMatchesFuncImport(
importRequiredType,
exportType,
exportDefinition))
{
return true;
}
if (ImportIsAction(importRequiredTypeDef, toDefinition)
&& ExportMatchesActionImport(importRequiredType, exportDefinition))
{
return true;
}
return false;
}
特殊なケース (など)IEnumerable<T>
ではLazy<T>
、インポートする型がジェネリック型に基づいているかどうかを判断する必要があることに注意してください。これは少し注意が必要です。
すべての構成情報が保存されると、必要なすべての情報が利用可能になるため、いつでも部品のインスタンス化を行うことができます。インスタンス化には、信頼できるActivatorクラスの使用と組み合わせたリフレクションの寛大な支援が必要であり、読者への演習として残されます。