Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中使用MEF仅获取必要的插件_C#_.net_Plugins_Mef - Fatal编程技术网

C# 在.NET中使用MEF仅获取必要的插件

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

我有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);
    }
}
我的问题是如何有选择地用完许多插件。这个例子只是让所有可用的插件运行它们,但是当我只想运行第一个插件或第二个插件时,我应该怎么做呢

例如,我可以只按如下方式运行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);
  }
}