如何在MEF中处理递归合成
本文关键字:递归 处理 MEF | 更新日期: 2023-09-27 18:22:11
考虑以下代码示例,该代码示例使用MEF创建Importer
类型的对象,该对象导入ImporterExporter
类型的对象而该对象又导入Exporter
类型的对象(即Importer -> ImporterExporter -> Exporter
)。目录由一个CompositionUtility
管理(对于本例来说显然是简化的)。
我知道MEF会递归地解析导入的零件。然而,因为我希望可以选择独立地实例化这些类中的每一个,所以每个具有导入的类也在其构造函数中组成自己,以解决这些导入。
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MefRecursionSample
{
class Program
{
static void Main(string[] args)
{
// var importerExporter = new ImporterExporter(); // include this and composition will work
var importer = new Importer();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
class CompositionUtility
{
static CompositionUtility()
{
var executingAssembly = Assembly.GetExecutingAssembly();
var assemblyCatalog = new AssemblyCatalog(executingAssembly);
_compositionContainer = new CompositionContainer(assemblyCatalog);
}
private static CompositionContainer _compositionContainer;
private static bool _isComposing;
public static void Compose(object part)
{
_compositionContainer.ComposeParts(part);
}
}
class Importer
{
public Importer()
{
CompositionUtility.Compose(this);
}
[Import]
public ImporterExporter ImporterExporter { get; set; }
}
[Export]
class ImporterExporter
{
public ImporterExporter()
{
CompositionUtility.Compose(this);
}
[Import]
public Exporter Exporter { get; set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
}
按原样运行代码会导致合成错误"MefRecursionSample.Importer类型的ComposablePart无法重新合成……",这显然是因为我试图明确地合成MEF也想合成的东西。
令我惊讶的是,当我包含Main
方法的第一行时,即创建一个没有MEF的ImporterExporter
类型的对象,这种"双重组合"不再引起异常。为什么?
此外,我如何使它工作,以便我可以独立地实例化其中的每一个,同时也使它们在链接时自行组成,就像在示例中一样。我想我会在CompositionUtility
上引入一个布尔标志_compositionInProgress
,并在设置该标志时立即从Compose()
返回,以避免递归组合。有更好的方法吗?
我考虑在CompositionUtility
的Compose
方法中设置的标志不起作用,因为在某些情况下,自动导入的字符串可能会中断。例如,在问题的例子中,如果Exporter
使用new
在其构造函数中实例化了一个类,并且这个类想要组成自己。在最初的解决方案下,该类对Ccompose
的调用将立即返回,从而使该类不被组合。
因为我希望类自行组成(因此,用户甚至不必了解MEF),所以唯一的解决方案是建立具有[Export]
属性的类不得调用Compose(this)
的规则。因为它们在导入时将由MEF自动组合,这将导致"双重组合",从而引发异常。
如果要求用[Export]
标记的类必须通过new
独立实例化,而不是仅通过MEF导入,那么它们必须有一个带有布尔标志的附加构造函数,当设置好时,该构造函数将触发该类的组合。然而,为了避免上述"双重组合",默认行为必须是无组合。
为什么不简单地这样做呢?
class Program
{
private static CompositionContainer _compositionContainer;
static void Main(string[] args)
{
//compose the container just one time in your app
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_compositionContainer = new CompositionContainer(assemblyCatalog);
var importer = _compositionContainer.GetExportedValue<Importer>();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
[Export]
class Importer
{
[ImportingConstructor]
public Importer(ImporterExporter imex)
{
this.ImporterExporter = imex;
}
public ImporterExporter ImporterExporter { get; private set; }
}
[Export]
class ImporterExporter
{
[ImportingConstructor]
public ImporterExporter(Exporter exporter)
{
this.Exporter = exporter;
}
public Exporter Exporter { get; private set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
您真正想做的(我认为)是调用容器。对对象而非ComposeParts执行SatisfyImportsOn()。
ComposeParts将所有导出树添加到目录中,而SatisfyImports一旦每个对象都是自己的,组成部分,就这样,没有递归导出的注册,所以你可以调用构造函数或使用导入构造函数,两者都可以。
詹姆斯。