无法使用元数据导入零件

时间:2013-08-21 14:28:34

标签: c# metadata mef .net-4.5

我正在尝试使用.NET 4.5导入部件并包含一个自定义MetadataAttribute,遵循命令式模型

下面,我已经包含了最简单的示例,它说明了问题。

执行此代码时,将调用Engine类构造函数,并传递一个空的枚举器,而不是两个明显属于项目一部分的插件。

目前我怀疑PluginMetadata属性,但我没有看到如何在没有它的情况下将元数据导入目录。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new RegistrationBuilder();
            builder.ForTypesDerivedFrom<IPlugIn>().Export<Lazy<IPlugIn, IPlugInMetadata>>();
            builder.ForType<Engine>().Export();
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder);
            var container = new CompositionContainer(catalog);

            var engine = container.GetExport<Engine>();
            engine.Value.Run();

        }
    }

    internal class Engine
    {
        private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; }
        public Engine(IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins)
        {
            PlugIns = plugins;
        }

        public void Run()
        {
            foreach (var plugIn in PlugIns)
            {
                Console.WriteLine("Starting {0}", plugIn.Metadata.Name);
                plugIn.Value.Work();
            }
        }
    }

    interface IPlugIn
    {
        void Work();
    }

    interface IPlugInMetadata
    {
        string Name { get; }
    }

    [MetadataAttribute]
    class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata
    {
        public PlugInMetadataAttribute(string name)
        {
            this.name = name;
        }

        private readonly string name;
        public string Name { get { return name; } }
    }

    [PlugInMetadata("PlugIn1")]
    class PlugIn1 : IPlugIn
    {
        public void Work()
        {
            Console.WriteLine("PlugIn 1 working");
        }
    }

    [PlugInMetadata("PlugIn2")]
    class PlugIn2 : IPlugIn
    {
        public void Work()
        {
            Console.WriteLine("PlugIn 2 working");
        }
    }
}

1 个答案:

答案 0 :(得分:1)

元数据接口不得包含任何具有setter的属性。您应该修改IPlugInMetadata接口,使其属性不会有任何setter,否则合成将失败:

interface IPlugInMetadata
{
    string Name { get; }
}

另外,您应该考虑让PlugInMetadataAttribute类继承自ExportAttribute而不是Attribute。这将允许使用此属性作为导出属性,您不必使用RegistrationBuilder


编辑:我认为我发现了您的问题

尝试在构造函数中使用ImportMany时,必须明确指定,因此构造函数应如下所示:

[ImportingConstructor]
public Engine([ImportMany] IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins)
{
    PlugIns = plugins;
}

或者,您可以选择将其作为属性导入:

[ImportMany]
private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; }

作为旁注,从ExportAttribute派生时,您希望包含自动将您的零件导出为IPlugIn的构造函数:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata
{
    public PlugInMetadataAttribute()
        : base(typeof(IPlugIn))
    {
    }

    public PlugInMetadataAttribute(string contractName)
        : base(contractName, typeof(IPlugIn))
    {
    }

    public string Name { get; set; }
}