2013-01-17 92 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(); 
       } 
      } 
     } 
    } 
}