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; 
    } 
}