MEF(托管扩展框架)和嵌套导入(包括示例) [英] MEF (Managed Extensibility Framework) and nested imports (incl. sample)

查看:83
本文介绍了MEF(托管扩展框架)和嵌套导入(包括示例)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

早上好,

我在MEF中使用嵌套导入时遇到了一个奇怪的问题。



我试着保持它相当基本的,所以我不会用细节惹恼你的人;)

也许有人经历过类似的行为,我只是不知道在哪里看。



我有一个 ModuleImporter 类,它暴露了一个 IModuleImporter 界面。



这个ModuleImporter是由我的主应用程序导入的,工作正常。



我还有 ExternalModule 导出 IExternalModule 界面的类,没什么特别的。



ModuleImporter 懒惰地导入许多 IExternalModule



如果我创建了一个实例TestI Form中的ModuleImporter完美地导入了发现的IExternalModules。



现在问题是如果ModuleImporter是由Ma导入的在应用程序 OnImportsSatisfied 的ExternalModule被调用两次!

我检查了ComposeParts方法,它只运行一次。



问题是下面显示的setter也被调用了两次。第一个发现了IExternalModule,第二个发现了IExternalModule。这会导致第一个正确的值(1个元素)被设置为第二个错误的值(0个元素)。



Good morning all,
I am struggeling with a strange problem using nested imports in MEF.

I try to keep it quite basic, so I do not annoy you people with the details ;)
Maybe somebody has experienced similar behavior, I just have no more clue where to look at.

I have a ModuleImporter class which exposes an IModuleImporter interface.

This ModuleImporter is imported by my main application which works fine.

I also have an ExternalModule class which exports an IExternalModule interface, nothing special.

The ModuleImporter imports many IExternalModule lazily.

If I create an instance of the ModuleImporter in a Test-Form it perfectly imports the discovered IExternalModules.

Now the problem is if the ModuleImporter is imported by the Main-Application OnImportsSatisfied of ExternalModule is called twice!
I checked the ComposeParts method, it only runs once.

The problem is that the below shown setter is also called twice. Frist with one discovered IExternalModule, secondly with zero discovered IExternalModule. That causes the first correct value (1 element) to be set to the second wrong value (0 elements).

[ImportMany]
public Lazy<IExternalModule>[] ModuleStorage { get; private set; }





我不知道从哪里开始......我检查内/外结构是否正确,但无法'找不到任何问题。有趣的是,只有在导入ModuleImporter时才会发生这种情况。如果它是手动构造的,那么IExternalModules的结果总是正确的(1)。

这让我相信它与嵌套有关......我重复自己;)



我添加了一个示例项目来说明问题:





I have no idea which direction to go from here... I checked if inner/outter structure is correct, but couldn't find any problems. Funny is also that it only happens if ModuleImporter is imported. If it is constructed manually the result of IExternalModules is always correct (1).
That lead me to belive that it has something to do with the nesting... I repead myself ;)

I added a sample project to illustrate the problem:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace TestRange
{
    public partial class frmImporterTest : Form
    {
        public frmImporterTest()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {


            // in this block there is one call to OnImportsSatisfied of Importer
            // and two calls to OnImportsSatisfied of ExtMod (should be only one)
            Importers importers = new Importers();
            List<IImporter> importersList = importers.ImportersList;

            foreach (IImporter imp in importersList)
            {
                List<IExtMod> extMods = imp.ExtMods;
                int a = 1;
            }

            int b = 0;

            // in this block there is one call to OnImportsSatisfied of Importer
            // and only one calls to OnImportsSatisfied of ExtMod (should be only one)
            Importer imp2 = new Importer();
            List<IExtMod> extMods2 = imp2.ExtMods;

            int c = 0;
        }
    }

    public interface IImporter
    {
        List<IExtMod> ExtMods { get; }
    }

    public interface IExtMod
    {
        string Name { get; }
    }

    public class Importers : MarshalByRefObject, IPartImportsSatisfiedNotification
    {

        public bool Loaded { get; protected set; }

        public Importers()
        {
            ComposeImporters();
        }


        private Lazy<IImporter>[] _importerStorage;
        [ImportMany]
        protected Lazy<IImporter>[] ImporterStorage
        {
            get { return _importerStorage; }
            private set { _importerStorage = value; }
        }

        public List<IImporter> ImportersList
        {
            get
            {
                if(ImporterStorage == null)
                {
                    return new List<IImporter>();
                }

                return ImporterStorage.Select(s => s.Value).ToList();
            }
        }
        

        public void ComposeImporters()
        {

            AggregateCatalog catalog = new AggregateCatalog();
            AssemblyCatalog cat = new AssemblyCatalog(this.GetType().Assembly);
            catalog.Catalogs.Add(cat);

            CompositionContainer container = new CompositionContainer(catalog);

            try
            {
                container.ComposeParts(this); 
            }
            catch (ReflectionTypeLoadException typeLoadException)
            {
                StringBuilder sb = new StringBuilder();

                foreach (Exception o in typeLoadException.LoaderExceptions)
                {
                    sb.AppendLine(String.Format("{0}", o));
                }

                Console.WriteLine(sb.ToString());

            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Loaded = true;
        }

        #region Implementation of IPartImportsSatisfiedNotification


        public void OnImportsSatisfied()
        {
            int i = 0;
        }

        #endregion
    }


    [PartCreationPolicy(CreationPolicy.Shared)]
    [Export(typeof(IImporter))]
    public class Importer : MarshalByRefObject, IImporter, IPartImportsSatisfiedNotification
    {
        
        public bool Loaded { get; protected set; }

        public Importer()
        {
            ComposeExMods();
        }


        private Lazy<IExtMod>[] _exModStorage;
        [ImportMany]
        protected Lazy<IExtMod>[] ExModStorage
        {
            get { return _exModStorage; }
            private set { _exModStorage = value; }
        }

        

        public void ComposeExMods()
        {

            AggregateCatalog catalog = new AggregateCatalog();
            AssemblyCatalog cat = new AssemblyCatalog(this.GetType().Assembly);
            catalog.Catalogs.Add(cat);

            CompositionContainer container = new CompositionContainer(catalog);

            try
            {
                container.ComposeParts(this); 
            }
            catch (ReflectionTypeLoadException typeLoadException)
            {
                StringBuilder sb = new StringBuilder();

                foreach (Exception o in typeLoadException.LoaderExceptions)
                {
                    sb.AppendLine(String.Format("{0}", o));
                }

                Console.WriteLine(sb.ToString());

            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Loaded = true;
        }

        #region Implementation of IPartImportsSatisfiedNotification


        public void OnImportsSatisfied()
        {
            int i = 0;
        }

        #endregion

        #region Implementation of IImporter

        public List<IExtMod> ExtMods
        {
            get
            {
                if (ExModStorage == null)
                {
                    return new List<IExtMod>();
                }

                return ExModStorage.Select(s => s.Value).ToList();
            }
        }

        #endregion
    }

    [PartCreationPolicy(CreationPolicy.Shared)]
    [Export(typeof(IExtMod))]
    public class ExtMod : IExtMod
    {
        public ExtMod()
        {
        }

        #region Implementation of IExtMod

        public string Name
        {
            get { return "Fubar"; }
        }

        #endregion
    }

}

















任何提示都很受欢迎,

有一个美好的一天

Andy









Any hint is kindly appreciated,
have a great day
Andy

推荐答案

嗨Andy,



采用简单的解决方案,只需使用通用的MEF导入器&装载机。我希望我的文章可以帮到你:



使用MEF完全懒惰DLL加载的最简单方法 [ ^ ]



最诚挚的问候,



Shai
Hi Andy,

Take the simple solution, just use a generic MEF importer & loader. I hope my article can help you:

The Simplest Way to use MEF Fully Lazy DLL Loading[^]

Best Regards,

Shai


这篇关于MEF(托管扩展框架)和嵌套导入(包括示例)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆