在.NET中只使用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 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 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); } }
编译后,我得到了我想要的东西。
> mono program.exe hello, world hello, world!!!!
我的问题是如何选择性地耗尽许多插件。 这个例子只是获取所有可用的插件来运行所有这些插件,但是当我只想运行第一个插件或第二个插件时,我该怎么办?
例如,我可以如下运行plugin2.dll吗?
public static void Main(string[] args) { Program p = new Program(); p.Run(); var message = messageSender.GetPlugin("plugin"); // ??? message.Send("hello, world"); }
解决了
基于这个网站 ,以及Matthew Abbott的回答。 我可以拿出这个工作代码。
接口代码(interface.cs)
using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; using System; public interface IMessageSender { void Send(string message); } public interface IMessageSenderMetadata { string Name {get; } string Version {get; } } [MetadataAttribute] [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class MessageMetadataAttribute : ExportAttribute, IMessageSenderMetadata { public MessageMetadataAttribute( string name, string version) : base(typeof(IMessageSender)) { Name = name; Version = version; } public string Name { get; set; } public string Version { get; set; } }
插件代码(Plugin.cs …)
using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; using System; [MessageMetadataAttribute("EmailSender1", "1.0.0.0")] public class EmailSender : IMessageSender { public void Send(string message) { Console.WriteLine(message + "????"); } }
Program.cs中
using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.Reflection; using System.Collections.Generic; using System; using System.Linq; public class Program { [ImportMany(typeof(IMessageSender), AllowRecomposition = true)] public IEnumerable<Lazy> Senders { get; set; } public static void Main(string[] args) { Program p = new Program(); p.Run(); var sender1 = p.GetMessageSender("EmailSender1","1.0.0.0"); sender1.Send("hello, world"); sender1 = p.GetMessageSender("EmailSender2","1.0.0.0"); sender1.Send("hello, world"); } public void Run() { Compose(); } public IMessageSender GetMessageSender(string name, string version) { return Senders .Where(l => l.Metadata.Name.Equals(name) && l.Metadata.Version.Equals(version)) .Select(l => l.Value) .FirstOrDefault(); } private void Compose() { var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new DirectoryCatalog(@"./")); var container = new CompositionContainer(catalog); container.ComposeParts(this); } }
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")
atrribute中的值生成一个项目实现您的接口,INameMetadata。
完成后,您可以进行一些过滤,因此将[Import]
重新定义为:
[ImportMany] public IEnumerable> Senders { get; set; }
MEF将创建的是可枚举的Lazy
实例,它们支持实例类型的延迟实例化。 我们可以查询为:
public IMessageSender GetMessageSender(string name) { return Senders .Where(l => l.Metadata.Name.Equals(name)) .Select(l => l.Value) .FirstOrDefault(); }
使用参数"EmailSender1"
为name
参数运行此操作将导致返回我们的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
实例意味着您将能够推迟实例的实例化,但这确实意味着每个延迟只能创建一个实例。 MEF框架的Silverlight变体还支持ExportFactory
类型,它允许您每次启动T
新实例,仍然为您提供丰富的元数据机制。
上述就是C#学习教程:在.NET中只使用MEF获取必要的插件分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1039060.html