代码之家  ›  专栏  ›  技术社区  ›  Aaron Powell

导出零件的MEF元数据

  •  4
  • Aaron Powell  · 技术社区  · 15 年前

    我正在寻找使用MEF为我正在构建的应用程序的插件系统。我想要在(GUID)上有一个标识符的每个组件,我想要能够查找它们。但是这个ID在处理导出的零件时也是有用的。

    有没有一种方法可以让我拥有一个元数据属性,该属性包含ID以及导出部分的属性(或方法),而不是让开发人员填写两次或使用反射从属性中查找它?

    2 回复  |  直到 15 年前
        1
  •  7
  •   Matthew Abbott    15 年前

    它可能是MEF元数据属性和抽象基类的混合体。我将我的插件合同定义为:

    public interface IPluginMetadata
    {
      Guid PluginId { get; }
    }
    
    public interface IPlugin : IPluginMetadata
    {
      void Initialise();
    }
    

    我强制要求 IPlugin 接口还继承了我们的元数据协定 IPluginMetadata . 接下来,我们可以创建一个自定义导出属性:

    [AttributeUsage(AttributeTargets.Class, Inherit = true), MetadataAttribute]
    public class ExportPluginAttribute : ExportAttribute, IPluginMetadata
    {
      public ExportPluginAttribute(string pluginId) : base(typeof(IPlugin))
      {
        if (string.IsNullOrEmpty(pluginId))
          throw new ArgumentException("'pluginId' is required.", "pluginId");
    
        PluginId = new Guid(pluginId);
      }
    
      public Guid PluginId { get; private set; }
    }
    

    不需要用元数据协定修饰export属性 IPluginMetadata公司 ,因为MEF无论如何都会投影属性,但我更愿意这样做,所以如果我对元数据协定引入更改,那么我的导出属性也应该更新。没有伤害,没有犯规。

    完成后,我们可以定义一个抽象基类,从中实现我们的插件契约:

    public abstract class PluginBase : IPlugin
    {
      protected PluginBase()
      {
        var attr = GetType()
          .GetCustomAttributes(typeof(ExportPluginAttribute), true)
          .Cast<ExportPluginAttribute>()
          .SingleOrDefault();
    
        PluginId = (attr == null) ? Guid.Empty : attr.PluginId;
      }
    
      public virtual Guid PluginId { get; private set; }
    
      public abstract void Initialise();
    }
    

    然后,我们可以通过抽象类的构造函数获取自定义属性,并相应地应用该属性。我们可以做到:

    public IPlugin GetPlugin(Guid id)
    {
      var plugin = container
        .GetExports<IPlugin, IPluginMetadata>()
        .Where(p => p.Metadata.PluginId == id)
        .Select(p => p.Value)
        .FirstOrDefault();
    
      return plugin;
    }
    

    以及:

    [ExportPlugin("BE112EA1-1AA1-4B92-934A-9EA8B90D622C")]
    public class MyPlugin : PluginBase
    {
      public override Initialise()
      {
        Console.WriteLine(PluginId);
      }
    }
    

    我们可以看出来 PluginId 通过导出的元数据以及插件的属性公开。

    这些代码都是未经测试的,但我希望它能将您推向正确的方向。

        2
  •  0
  •   Wim Coenen    15 年前

    将GUID放入常量中,并将其用于属性和元数据:

    [Export(typeof(IFoo))]
    [ExportMetadata("GUID", _guid)]
    public class Foo : IFoo
    {
        private const string _guid = "abc";
    
        public string Guid { get { return _guid; } }
    }
    

    注意,您不能使用 Guid 键入而不是 string ,因为这是 const 关键字。

    推荐文章