2013-01-17 57 views
2

我使用无属性的方法来配置MEF。
我阅读下面的文章:
http://msdn.microsoft.com/en-us/magazine/jj133818.aspx
http://blogs.microsoft.co.il/blogs/bnaya/archive/2013/01/12/mef-2-0-mini-series-part-4-fluent-import.aspxMEF 2:导入很多

测试代码(控制台应用程序项目,.NET 4.5):

using System; 
using System.Collections.Generic; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.ComponentModel.Composition.Registration; 
using System.Linq; 

namespace MEF2 
{ 
    public interface IPlugin 
    { 
     void Run(); 
    } 

    public interface IPluginMetadata 
    { 
     string Name { get; } 
     string Version { get; } 
    } 

    [MetadataAttribute] 
    [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] 
    public class PluginMetadataAttribute : ExportAttribute, IPluginMetadata 
    { 
     public string Name { get; set; } 
     public string Version { get; set; } 

     public PluginMetadataAttribute(string name, string version) 
      : base(typeof(IPlugin)) 
     { 
      Name = name; 
      Version = version; 
     } 
    } 

    [PluginMetadata("Plugin1", "1.0.0.0")] 
    public class Plugin1 : IPlugin 
    { 
     public void Run() 
     { 
      Console.WriteLine("Plugin1 runed"); 
     } 
    } 

    [PluginMetadata("Plugin2", "2.0.0.0")] 
    public class Plugin2 : IPlugin 
    { 
     public void Run() 
     { 
      Console.WriteLine("Plugin2 runed"); 
     } 
    } 


    class Program 
    { 
     CompositionContainer container; 
     IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins = Enumerable.Empty<Lazy<IPlugin, IPluginMetadata>>(); 

     static void Main(string[] args) 
     { 
      var program = new Program(); 

      foreach (var plugn in program.plugins) { 
       Console.WriteLine("{0}, {1}", plugn.Metadata.Name, plugn.Metadata.Version); 
       plugn.Value.Run(); 
      } 
     } 

     Program() 
     { 
      var builder = new RegistrationBuilder(); 
      builder 
       .ForTypesDerivedFrom<IPlugin>() 
       .Export<IPlugin>(); 
      builder 
       .ForType<Program>() 
       .Export() 
       .ImportProperties<IPlugin>(
        propertyFilter => true, 
        (propertyInfo, importBuilder) => { 
         importBuilder.AsMany(); 
        } 
       ); 

      var catalog = new AggregateCatalog(
       new AssemblyCatalog(typeof(Program).Assembly, builder) 
      ); 

      container = new CompositionContainer(catalog); 
      container.ComposeParts(this); 
     } 
    } 
} 

出口工作正常。
但是,当我尝试导入很多它不起作用。
请帮我解决这个问题。

回答

1

由于导出属于(声明式),因此这不是无属性(必要)方法。您的自定义元数据属性来自ExportAttribute

为使该代码工作,你需要做到以下几点:

  • 取下构造函数代码势在必行出口。
  • 将注册生成器传递给AssemblyCatalog。如果没有这个注册生成器不能使用。
  • 使用Lazy<IPlugin, IPluginMetadata>更新基于约定的导入,因为这是导出的内容。
  • GetExports替换电话ComposeParts

更新后的构造函数代码为:

  var builder = new RegistrationBuilder(); 

      builder 
       .ForType<Program>() 
       .Export()     
       .ImportProperties<Lazy<IPlugin, IPluginMetadata>>(
        propertyFilter => true, 
        (propertyInfo, importBuilder) => 
        { 
         importBuilder.AsMany(); 
        } 
       ); 

      var catalog = new AggregateCatalog(
       new AssemblyCatalog(typeof(Program).Assembly, builder) 
      ); 

      container = new CompositionContainer(catalog); 
      //container.ComposeParts(this); 
      plugins = container.GetExports<IPlugin, IPluginMetadata>(); 

我不知道如何使这项工作,ComposeParts呢。我会看看它。此外,自定义元数据不必从ExportAttribute派生。它可以从System.Attribute派生。这将让你有一个必要的出口。

1

谢谢,我发现了这个问题的解决方案。
奇怪的是,我从来没有找到这样的例子。
示例代码:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.ComponentModel.Composition.Registration; 

namespace MEF2 
{ 
    public interface IPlugin 
    { 
     void Run(); 
    } 

    public interface IPluginMetadata 
    { 
     string Name { get; } 
     string Version { get; } 
    } 

    [MetadataAttribute] 
    [AttributeUsage(AttributeTargets.Class, AllowMultiple=false)] 
    public class PluginMetadataAttribute : ExportAttribute, IPluginMetadata 
    { 
     public string Name { get; set; } 
     public string Version { get; set; } 

     public PluginMetadataAttribute(string name, string version) 
      : base(typeof(IPlugin)) 
     { 
      Name = name; 
      Version = version; 
     } 
    } 

    [PluginMetadata("Plugin1", "1.0.0.0")] 
    public class Plugin1 : IPlugin 
    { 
     public void Run() 
     { 
      Console.WriteLine("Plugin1 runed"); 
     } 
    } 

    [PluginMetadata("Plugin2", "2.0.0.0")] 
    public class Plugin2 : IPlugin 
    { 
     public void Run() 
     { 
      Console.WriteLine("Plugin2 runed"); 
     } 
    } 

    public class PluginStore 
    { 
     public IEnumerable<Lazy<IPlugin, IPluginMetadata>> Plugins { get; private set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var builder = new RegistrationBuilder(); 
      builder 
       .ForTypesDerivedFrom<IPlugin>() 
       .Export<IPlugin>(); 
      builder 
       .ForType<PluginStore>() 
       .Export() 
       .ImportProperties(
        propertyFilter => true, 
        (propertyInfo, importBuilder) => { 
         importBuilder.AsMany(); 
        } 
       ); 

      var catalog = new AssemblyCatalog(typeof(PluginStore).Assembly, builder); 

      using (var container = new CompositionContainer(catalog)) { 
       var pluginStore = container.GetExport<PluginStore>().Value; 

       foreach (var plugin in pluginStore.Plugins) { 
        Console.WriteLine("{0}, {1}", plugin.Metadata.Name, plugin.Metadata.Version); 
        plugin.Value.Run(); 
       } 
      } 
     } 
    } 
}