.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<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\");
}
解决了 基于该站点以及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<IMessageSender, IMessageSenderMetadata>> 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\")
属性中的值,生成一个实现接口interface11ѭ的项目。 完成此操作后,您可以进行一些过滤,因此将
[Import]
重新定义为以下内容:
[ImportMany]
public IEnumerable<Lazy<IMessageSender, INameMetadata>> Senders { get; set; }
MEF将创建一个ѭ15个实例的枚举,这些实例支持实例类型的延迟实例化。我们可以查询为:
public IMessageSender GetMessageSender(string name)
{
  return Senders
    .Where(l => l.Metadata.Name.Equals(name))
    .Select(l => l.Value)
    .FirstOrDefault();
}
使用
name
参数的
\"EmailSender1\"
参数运行此命令将导致返回our19ѭ实例。需要注意的重要一点是,我们基于查询与类型关联的元数据的方式,选择了要使用的特定实例。 您可以再进一步,可以将
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>
实例意味着您将能够推迟实例的实例化,但这确实意味着每个惰性实例只能创建一个实例。 MEF框架的Silverlight变体还支持
ExportFactory<T, TMetadata>
类型,它允许您每次启动
T
的新实例,而列表仍然为您提供丰富的元数据机制。     

要回复问题请先登录注册