2011-08-26 59 views
5

我想將MEF用作我的項目的DI。我有一個項目,每個應該組成的類都駐留在那裏(它們共享一個接口)。現在我想通過指定元數據值來創建其中的一個。這裏的定義:帶元數據的MEF GetExportedValue

public interface IGatewayResponseReader 
{ 
    object Read(string msg); 
} 

[Export(typeof(IGatewayResponseReader))] 
[ExportMetadata(G3Reader.META_KEY, "value1")] 
public class TestReader1 : IGatewayResponseReader 
{ 
    ... 
} 

[Export(typeof(IGatewayResponseReader))] 
[ExportMetadata(G3Reader.META_KEY, "value2")] 
public class TestReader2 : IGatewayResponseReader 
{ 
    ... 
} 

現在我想通過MEF建立TestReader1的實例,但我不知道如何通過元數據通過CompositionContainer中進行篩選。我想要類似於

Container.GetExportedValue<IGatewayResponseReader>(); 

但是指定元數據以選擇要創建的類實例。

非常感謝您的幫助。

謝謝。

回答

6

通過@Dmitry Ornatsky provied的答案是正確的,但出口提供元數據的首選方法是使用自定義導出屬性使用強類型的元數據:

public interface IGatewayResponseReaderMetadata 
{ 
    string Key { get; } 
} 

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] 
public class GatewayResponseReaderExportAttribute : ExportAttribute 
{ 
    public GatewayResponseReaderExportAttribute(string key) 
     : base(typeof(IGatewayResponseReader)) 
    { 
     this.Key = key; 
    } 

    public string Key { get; set; } 
} 

[GatewayResponseReaderExport("value1")] 
public class TestReader1 : IGatewayResponseReader 
{ 
} 

代碼查找然後可以使導入類型安全。請注意,這是一個好主意,以檢查是否導入訪問Value屬性之前不爲空:

class Program 
{ 
    [ImportMany] 
    private List<Lazy<IGatewayResponseReader, IGatewayResponseReaderMetadata>> _readers; 

    static void Main(string[] args) 
    { 
     CompositionContainer container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly())); 

     Program program = new Program(); 
     container.SatisfyImportsOnce(program); 


     var reader = program._readers.FirstOrDefault(r => r.Metadata.Key == "value1"); 
     if (reader != null) 
      reader.Value.Read(...); 
    } 
} 
+0

感謝菲爾,我感謝你的幫助:)。該死的,我試過這種方式,並沒有工作,因爲我不知道MetadataAttribute :(我花了5個小時試圖弄清楚。謝謝 – Davita

4
class Program 
{ 
    [ImportMany] 
    private List<Lazy<IGatewayResponseReader, IDictionary<string, object>>> _readers; 

    static void Main(string[] args) 
    { 
     CompositionContainer container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly())); 

     Program program = new Program(); 
     container.SatisfyImportsOnce(program); 
     var result = program._readers.Where(r =>    
      r.Metadata.ContainsKey(G3Reader.META_KEY) && (string)r.Metadata[G3Reader.META_KEY] == "value1") 
      .First().Value; 
    } 
}