【问题标题】:MEF Metadata from the exported parts来自导出部件的 MEF 元数据
【发布时间】:2010-11-21 11:11:04
【问题描述】:

我希望将 MEF 用于我正在构建的应用程序的插件系统。我希望每个组件在(GUID)上都有一个我希望能够查找的标识符。但这个 ID 在处理导出部件时也很有用。

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

【问题讨论】:

    标签: metadata mef


    【解决方案1】:

    它可能是 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; }
    }
    

    您不需要使用元数据合约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 通过导出的元数据以及我们插件的属性公开。

    该代码均未经测试,但我希望它能将您推向正确的方向。

    【讨论】:

    • 这就是我认为我必须采用的方法,尽管我会指出您不能将 Guid 作为元数据对象的属性类型。不是 huge 交易,我只是使用 CodeContract 在属性的 ctor 中强制执行它
    【解决方案2】:

    将 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 关键字不允许这样做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-01
      • 2011-06-18
      • 2013-08-24
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      相关资源
      最近更新 更多