Получение только необходимых плагинов с MEF in.NET
у меня есть интерфейс IMessageSender.
using System.ComponentModel.Composition;
public interface IMessageSender
{
void Send(string message);
}
и у меня есть два плагина, которые реализуют этот интерфейс. Это плагин.цезий.
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);
}
}
после компиляции, я получаю то, что хочу.
> 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");
}
решить
на основе этот сайт, и ответ Мэтью Эббота. Я придумал этот код.
код интерфейса (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.цезий. ..)
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 + "????");
}
}
1 ответов
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 будет делать, это генерировать проект реализация вашего интерфейса,INameMetadata
использовать значение, хранящееся в ExportMetadata("Name", "EmailSender1")
atrribute.
после того, как вы это сделали, вы можете сделать небольшую фильтрацию, поэтому переопределите свой [Import]
что-то вроде:
[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }
то, что MEF создаст, является перечисляемым из Lazy<T, TMetadata>
экземпляры, которые поддерживают отложенный экземпляр вашего типа экземпляра. Мы можем запросить как:
public IMessageSender GetMessageSender(string name)
{
return Senders
.Where(l => l.Metadata.Name.Equals(name))
.Select(l => l.Value)
.FirstOrDefault();
}
запуск этого с аргументом "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<T, TMetadata>
экземпляры означает, что вы сможете отложить создание экземпляра экземпляра, но это означает, что только один экземпляр может быть создан на lazy. Вариант Silverlight фреймворка MEF также поддерживает ExportFactory<T, TMetadata>
тип, который позволяет создавать новые экземпляры T
каждый раз, whilist по-прежнему предоставляет вам богатый механизм метаданных.