0

我正在尝试使用 .NET 4.5 按照命令式模型导入部件并包含自定义 MetadataAttribute

下面,我提供了最简单的例子来说明问题。

执行此代码时,Engine调用类构造函数,并传递一个空 Enumerator,而不是显然属于项目的两个插件。

目前我怀疑 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");
        }
    }
}
4

1 回答 1

1

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

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; }
}
于 2013-09-06T12:49:42.380 回答