如何在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()返回,以避免递归组合。有更好的方法吗?

如何在MEF中处理递归合成

我考虑在CompositionUtilityCompose方法中设置的标志不起作用,因为在某些情况下,自动导入的字符串可能会中断。例如,在问题的例子中,如果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一旦每个对象都是自己的,组成部分,就这样,没有递归导出的注册,所以你可以调用构造函数或使用导入构造函数,两者都可以。

詹姆斯。