2013-08-21 46 views
0

我試圖進口零部件,包括自定義MetadataAttribute,繼勢在必行模型,使用.NET 4.5無法導入部分與元數據

下面,我已經包括了最簡單的例子,我可以,這說明問題。

執行此代碼時,將調用Engine類構造函數,並傳遞一個空的Enumerator,而不是兩個插件,這兩個插件顯然是項目的一部分。

目前我懷疑PluginMetadata屬性,但我沒有看到如何在沒有它的情況下將元數據放入目錄。

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

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var builder = new RegistrationBuilder(); 
      builder.ForTypesDerivedFrom<IPlugIn>().Export<Lazy<IPlugIn, IPlugInMetadata>>(); 
      builder.ForType<Engine>().Export(); 
      var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder); 
      var container = new CompositionContainer(catalog); 

      var engine = container.GetExport<Engine>(); 
      engine.Value.Run(); 

     } 
    } 

    internal class Engine 
    { 
     private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; } 
     public Engine(IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins) 
     { 
      PlugIns = plugins; 
     } 

     public void Run() 
     { 
      foreach (var plugIn in PlugIns) 
      { 
       Console.WriteLine("Starting {0}", plugIn.Metadata.Name); 
       plugIn.Value.Work(); 
      } 
     } 
    } 

    interface IPlugIn 
    { 
     void Work(); 
    } 

    interface IPlugInMetadata 
    { 
     string Name { get; } 
    } 

    [MetadataAttribute] 
    class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata 
    { 
     public PlugInMetadataAttribute(string name) 
     { 
      this.name = name; 
     } 

     private readonly string name; 
     public string Name { get { return name; } } 
    } 

    [PlugInMetadata("PlugIn1")] 
    class PlugIn1 : IPlugIn 
    { 
     public void Work() 
     { 
      Console.WriteLine("PlugIn 1 working"); 
     } 
    } 

    [PlugInMetadata("PlugIn2")] 
    class PlugIn2 : IPlugIn 
    { 
     public void Work() 
     { 
      Console.WriteLine("PlugIn 2 working"); 
     } 
    } 
} 

回答

1

元數據接口不能與setter具有任何屬性。你應該修改IPlugInMetadata接口,因此它的性能不會有任何的制定者,否則構成將失敗:

interface IPlugInMetadata 
{ 
    string Name { get; } 
} 

此外,你應該考慮從ExportAttribute而不是Attribute讓你PlugInMetadataAttribute類繼承。這將允許使用此屬性作爲導出屬性,您不必使用RegistrationBuilder


編輯:我想我找到了你的問題

當試圖在構造函數中使用ImportMany,你必須指定明確這樣,所以你的構造應該是這樣的:

[ImportingConstructor] 
public Engine([ImportMany] IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> plugins) 
{ 
    PlugIns = plugins; 
} 

或者,您可以選擇將其作爲屬性導入:

[ImportMany] 
private IEnumerable<Lazy<IPlugIn, IPlugInMetadata>> PlugIns { get; set; } 

作爲一個側面說明,從ExportAttribute派生時,你想包括自動導出一部分IPlugIn構造函數:

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
class PlugInMetadataAttribute : ExportAttribute, IPlugInMetadata 
{ 
    public PlugInMetadataAttribute() 
     : base(typeof(IPlugIn)) 
    { 
    } 

    public PlugInMetadataAttribute(string contractName) 
     : base(contractName, typeof(IPlugIn)) 
    { 
    } 

    public string Name { get; set; } 
} 
+0

阿迪我已經試過你的建議,這當然有可能響起。我編輯了我原來的問題,並相應更新了代碼。但是引擎仍然沒有收到任何插件。必須有更多的難題。 –

+0

@RalphShillington查看我的編輯 –

+0

完美---顯然我不能獎勵賞金直到明天。 –