2011-08-26 5 views
5

Je souhaite utiliser MEF comme DI pour mon projet. J'ai 1 projet et toutes les classes qui devraient être composées y résident (ils partagent une interface). Maintenant, je veux en créer un en spécifiant une valeur de métadonnées. Voici les définitions:MEF GetExportedValue avec les métadonnées

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

Maintenant, je veux créer une instance de TestReader1 par MEF, mais je ne sais pas comment filtrer par des métadonnées par CompositionContainer. Je veux quelque chose comme

Container.GetExportedValue<IGatewayResponseReader>(); 

Mais pour spécifier les métadonnées pour choisir l'instance de classe à créer.

Votre aide est grandement appréciée.

Merci.

Répondre

6

La réponse provied par @Dmitry Ornatsky est correcte, mais la meilleure façon de fournir des métadonnées d'exportation est d'utiliser les métadonnées fortement typé en utilisant un attribut d'exportation personnalisé:

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

Le code pour rechercher une importation peut alors être sécurisée. Notez que c'est une bonne idée de vérifier si l'importation est non nul avant d'accéder à la propriété 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

Merci Phil, je vous remercie de votre aide :). Merde, j'ai essayé de cette façon et ne fonctionnait pas parce que je ne savais pas sur MetadataAttribute :(J'ai passé 5 heures à essayer de le comprendre. – 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; 
    } 
} 
Questions connexes