使用MEF初始化ExportFactory

时间:2014-06-10 03:19:33

标签: c# mef autofac

  1. 情景
    1. 应用程序有多个部分。
    2. 每个部分都在单独的dll中并实现接口IFoo
    3. 所有这些dll都存在于同一目录(插件)
    4. 应用程序可以实例化每个部分的多个实例
  2. 以下是接口,部分(导出)和导入的代码段。我遇到的问题是,“工厂”对象用空列表初始化。

    但是,如果我尝试使用container.Resolve(typeof(IEnumerable< IFoo>)),我会得到该部分的对象。但这不符合我的目的(第4点)。谁能指出我在这里做错了什么?

    public interface IFoo
    {
        string Name { get; }
    }
    
    public interface IFooMeta
    {
        string CompType { get; }
    }
    

    在单独的Dll中实施IFoo

    [ExportMetadata("CompType", "Foo1")]
    [Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class Foo1 : IFoo
    {
        public string Name
        {
            get { return this.GetType().ToString(); }
        }
    }
    

    加载所有部件并根据需要实例化的主应用程序

    class PartsManager
        {
            [ImportMany]
            private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;
    
            public PartsManager()
            {
                IContainer container = ConstructContainer();    
                factories = (IEnumerable<ExportFactory<IFoo, IFooMeta>>)
                       container.Resolve(typeof(IEnumerable<ExportFactory<IFoo, IFooMeta>>));    
            }    
    
            private static IContainer ConstructContainer()
            {
                var catalog = new DirectoryCatalog(@"C:\plugins\");
                var builder = new ContainerBuilder();         
                builder.RegisterComposablePartCatalog(catalog);
    
                return builder.Build();
            }
    
            public IFoo GetPart(string compType)
            {
                var matchingFactory = factories.FirstOrDefault(
                    x => x.Metadata.CompType == compType);
                if (factories == null)
                {
                    return null; 
                }
                else
                {
                    IFoo foo = matchingFactory.CreateExport().Value;
                    return foo;
                }
            }
        }
    

2 个答案:

答案 0 :(得分:0)

这似乎是ContainerBuilder的一个问题。我尝试使用CompositionContainer的替代方法,它没有障碍。粘贴修改后的方法的代码片段。

    public PartsManager()
    {
         ConstructContainer();
    }

    private void ConstructContainer()
    {
        var catalog = new DirectoryCatalog(@"C:\plugins\");
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
        container.SatisfyImportsOnce(this);
    }

答案 1 :(得分:0)

它似乎是Autofac中的known issue,目前已关闭&#34;无法修复&#34;分辨率。

如果您从Autofac中移除依赖关系,如下所示,它将起作用:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.ComponentModel.Composition;
using System.Reflection;

namespace SO24132313
{
    public interface IFoo
    {
        string Name { get; }
    }

    public interface IFooMeta
    {
        string CompType { get; }
    }

    [ExportMetadata("CompType", "Foo1")]
    [Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class Foo1 : IFoo
    {
        public string Name
        {
            get { return GetType().ToString(); }
        }
    }


    class PartsManager
    {
        [ImportMany]
        private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;

        public PartsManager()
        {
            ConstructContainer(this);
        }

        private static void ConstructContainer(PartsManager p)
        {
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var c = new CompositionContainer(catalog);
            c.ComposeParts(p);
        }

        public IFoo GetPart(string compType)
        {
            var matchingFactory = factories.FirstOrDefault(
                x => x.Metadata.CompType == compType);
            if (factories == null)
            {
                return null;
            }
            else
            {
                IFoo foo = matchingFactory.CreateExport().Value;
                return foo;
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            PartsManager a = new PartsManager();
            IFoo bla = a.GetPart("Foo1");
            Console.WriteLine(bla);
        }
    }
}