Получение только необходимых плагинов с 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 по-прежнему предоставляет вам богатый механизм метаданных.