2011-08-26 15 views
5

Quiero usar MEF como DI para mi proyecto. Tengo 1 proyecto y todas las clases que deben componerse residen allí (comparten una interfaz). Ahora quiero crear uno de ellos especificando un valor de metadato. He aquí las definiciones:MEF GetExportedValue con los metadatos

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 
{ 
    ... 
} 

Ahora quiero crear una instancia de TestReader1 a través del MEF, pero no saben cómo va a filtrar a través de metadatos CompositionContainer. Quiero algo como

Container.GetExportedValue<IGatewayResponseReader>(); 

Pero para especificar los metadatos para elegir qué instancia de clase crear.

Su ayuda es muy apreciada.

Gracias.

Respuesta

6

La respuesta provied por @Dmitry Ornatsky es correcta, pero la mejor forma de proporcionar metadatos de exportación es el uso de metadatos inflexible de tipos utilizando un atributo de exportación personalizada:

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

El código para buscar una importación puede hacerse segura para el tipo. Tenga en cuenta que es una buena idea para comprobar si la importación no es nulo antes de acceder a la propiedad 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

Gracias Phil, aprecio su ayuda :). Maldita sea, lo intenté de esa manera y no funcionó porque no sabía sobre MetadataAttribute :(Pasé 5 horas tratando de resolverlo. Gracias – 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; 
    } 
}