我正在尝试使用.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");
}
}
}
答案 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; }
}