C# 在.NET中使用MEF仅获取必要的插件
我有IMessageSender接口C# 在.NET中使用MEF仅获取必要的插件,c#,.net,plugins,mef,C#,.net,Plugins,Mef,我有IMessageSender接口 using System.ComponentModel.Composition; public interface IMessageSender { void Send(string message); } 我有两个插件实现这个接口。这是plugin.cs using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using
using System.ComponentModel.Composition;
public interface IMessageSender
{
void Send(string message);
}
我有两个插件实现这个接口。这是plugin.cs
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System;
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
这是plugin2.cs
[Export(typeof(IMessageSender))]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message + "!!!!");
}
}
我有这个代码来运行这些插件和MEF
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Collections.Generic;
using System;
public class Program
{
[ImportMany]
public IEnumerable<IMessageSender> MessageSender { get; set; }
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
foreach (var message in p.MessageSender) {
message.Send("hello, world");
}
}
public void Run()
{
Compose();
}
private void Compose()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(@"./"));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
我的问题是如何有选择地用完许多插件。这个例子只是让所有可用的插件运行它们,但是当我只想运行第一个插件或第二个插件时,我应该怎么做呢
例如,我可以只按如下方式运行plugin2.dll吗
public static void Main(string[] args)
{
Program p = new Program();
p.Run();
var message = messageSender.GetPlugin("plugin"); // ???
message.Send("hello, world");
}
解决了的
基于,和马修·阿伯特的答案。我可以想出这个工作代码
接口代码(interface.cs)
插件代码(Plugin.cs…)
Program.cs
使用System.ComponentModel.Composition;
使用System.ComponentModel.Composition.Hosting;
运用系统反思;
使用System.Collections.Generic;
使用制度;
使用System.Linq;
公共课程
{
[ImportMany(typeof(IMessageSender),AllowRecomposition=true)]
公共IEnumerable发件人{get;set;}
公共静态void Main(字符串[]args)
{
程序p=新程序();
p、 Run();
var sender1=p.GetMessageSender(“EmailSender1”、“1.0.0.0”);
发送者1.发送(“你好,世界”);
sender1=p.GetMessageSender(“EmailSender2”、“1.0.0.0”);
发送者1.发送(“你好,世界”);
}
公开募捐
{
撰写();
}
公共IMessageSender GetMessageSender(字符串名称,字符串版本)
{
回信人
.Where(l=>l.Metadata.Name.Equals(Name)和&l.Metadata.Version.Equals(Version))
.选择(l=>l.Value)
.FirstOrDefault();
}
私有无效组合()
{
var catalog=new AggregateCatalog();
catalog.Catalogs.Add(新目录目录(@“/”);
var容器=新的合成容器(目录);
容器。组件(本);
}
}
MEF支持导出自定义元数据以随导出的类型一起导出。您需要做的是,首先定义一个接口,MEF将使用该接口创建包含元数据的代理对象。在您的示例中,每个导出可能需要一个唯一的名称,因此我们可以定义:
public interface INameMetadata
{
string Name { get; }
}
然后,您需要做的是确保为每个需要该元数据的导出分配该元数据:
[Export(typeof(IMessageSender)), ExportMetadata("Name", "EmailSender1")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
MEF将要做的是使用ExportMetadata(“Name”,“EmailSender1”)
属性中存储的值生成一个项目,作为接口的实现,INameMetadata
完成后,您可以进行一些过滤,因此可以将[Import]
重新定义为类似以下内容:
[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }
使用name
参数的参数“EmailSender1”
运行此操作将导致返回我们的EmailSender
实例。需要注意的重要一点是,我们如何根据查询与类型关联的元数据来选择要使用的特定实例
您可以更进一步,将Export
和ExportMetadata
属性合并为单个属性,例如:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false), MetadataAttribute]
public class ExportMessageSenderAttribute : ExportAttribute, INameMetadata
{
public ExportMessageSenderAttribute(string name)
: base(typeof(IMessageSender))
{
Name = name;
}
public string Name { get; private set; }
}
这允许我们使用单个属性导出类型,同时仍提供其他元数据:
[ExportMessageSender("EmailSender2")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
显然,以这种方式查询将为您提供一个设计决策。使用
Lazy
实例意味着您可以推迟实例的实例化,但这确实意味着每个Lazy只能创建一个实例。MEF框架的Silverlight变体还支持ExportFactory
类型,它允许您每次启动T
的新实例,而这仍然为您提供了丰富的元数据机制 没有足够的时间回答完整的问题,但您需要研究的是[ExportMetadata]
,可能还有[ImportMany]IEnumerable
(您可以创建一个元数据接口,其中包含您希望看到的属性)。您可能还需要考虑创建自己的目录类,该类可以集中您的筛选,以便您的其余[Import]位置看起来干净(好像只有一个[Import]需要解析)
[Export(typeof(IMessageSender)), ExportMetadata("Name", "EmailSender1")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}
[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }
public IMessageSender GetMessageSender(string name)
{
return Senders
.Where(l => l.Metadata.Name.Equals(name))
.Select(l => l.Value)
.FirstOrDefault();
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false), MetadataAttribute]
public class ExportMessageSenderAttribute : ExportAttribute, INameMetadata
{
public ExportMessageSenderAttribute(string name)
: base(typeof(IMessageSender))
{
Name = name;
}
public string Name { get; private set; }
}
[ExportMessageSender("EmailSender2")]
public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine(message);
}
}