2012-06-11 7 views
5

Non capisco MEF molto bene, quindi spero che questa sia una semplice soluzione di come penso che funzioni.MEF GetExports <T, TMetaDataView> non restituisce nulla con AllowMultiple = True

Sto cercando di utilizzare MEF per ottenere alcune informazioni su una classe e su come dovrebbe essere utilizzata. Sto usando le opzioni dei metadati per cercare di ottenere questo. I miei interfacce e attributo aspetto:

public interface IMyInterface 
{ 
} 

public interface IMyInterfaceInfo 
{ 
    Type SomeProperty1 { get; } 
    double SomeProperty2 { get; } 
    string SomeProperty3 { get; } 
} 

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 
public class ExportMyInterfaceAttribute : ExportAttribute, IMyInterfaceInfo 
{ 
    public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3) 
     : base(typeof(IMyInterface)) 
    { 
     SomeProperty1 = someProperty1; 
     SomeProperty2 = someProperty2; 
     SomeProperty3 = someProperty3; 
    } 

    public Type SomeProperty1 { get; set; } 
    public double SomeProperty2 { get; set; } 
    public string SomeProperty3 { get; set; } 
} 

La classe che è decorato con l'attributo assomiglia a questo:

[ExportMyInterface(typeof(string), 0.1, "whoo data!")] 
[ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")] 
public class DecoratedClass : IMyInterface 
{ 
} 

Il metodo che sta cercando di utilizzare l'importazione assomiglia a questo:

private void SomeFunction() 
{ 
    // CompositionContainer is an instance of CompositionContainer 
    var myExports = CompositionContainer.GetExports<IMyInterface, IMyInterfaceInfo>(); 
} 

Nel mio caso myExports è sempre vuoto. Nel mio CompositionContainer, ho una parte nel mio catalogo che ha due ExportDefinitions, entrambi con il seguente ContractName: "MyNamespace.IMyInterface". Anche lo Metadata viene caricato correttamente per le mie esportazioni.

Se rimuovo il setter AllowMultiple e includo solo un attributo esportato, la variabile myExports ha ora la singola esportazione con i relativi metadati caricati.

Cosa sto sbagliando?

EDIT: Se io uso debolmente tipizzato metadati, la mia esportazione è improvvisamente soddisfatta:

var myExports = CompositionContainer.GetExports<IMyInterface, IDictionary<string, object>>(); 

Tutte le idee perché?

risposta

9

È noto che MEF ha alcuni problemi quando si tratta di AllowMultiple = true. Per una spiegazione completa si potrebbe ad esempio guardare here, comunque deriva dal fatto che i metadati vengono salvati in un dizionario in cui i valori sono matrici quando AllowMultiple è true, e tale cosa non può essere mappata su IMyInterfaceInfo.

Questa è la soluzione che uso. Prima di tutto l'attributo dovrebbe derivare da Attribute, non dal ExportAttribute:

[MetadataAttribute] 
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 
public class ExportMyInterfaceAttribute : Attribute, IMyInterfaceInfo 
{ 
    public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3) 

    { 
     SomeProperty1 = someProperty1; 
     SomeProperty2 = someProperty2; 
     SomeProperty3 = someProperty3; 
    } 

    public Type SomeProperty1 { get; set; } 
    public double SomeProperty2 { get; set; } 
    public string SomeProperty3 { get; set; } 
} 

Ciò significa che la classe esportato dovrebbe avere 3 attributi, uno standard per l'export e gli attributi vostra abitudine:

[Export(typeof(IMyInterface))] 
[ExportMyInterface(typeof(string), 0.1, "whoo data!")] 
[ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")] 
public class DecoratedClass : IMyInterface 

Poi si deve per definire una vista per i metadati che verranno importati. Questo deve avere un costruttore che prende l'IDictionary come parametro. Qualcosa di simile a questo:

public class MyInterfaceInfoView 
{ 
    public IMyInterfaceInfo[] Infos { get; set; } 

    public MyInterfaceInfoView(IDictionary<string, object> aDict) 
    { 
     Type[] p1 = aDict["SomeProperty1"] as Type[]; 
     double[] p2 = aDict["SomeProperty2"] as double[]; 
     string[] p3 = aDict["SomeProperty3"] as string[]; 

     Infos = new ExportMyInterfaceAttribute[p1.Length]; 
     for (int i = 0; i < Infos.Length; i++) 
      Infos[i] = new ExportMyInterfaceAttribute(p1[i], p2[i], p3[i]); 
    } 
} 

Ora si dovrebbe essere in grado di chiamare con successo

var myExports = CompositionContainer.GetExports<IMyInterface, MyInterfaceInfoView>(); 
+0

Sì, questo è quello che ho finito per fare, dopo aver letto il seguente articolo: http://blogs.microsoft.co. il/blog/bnaya/archive/2010/01/29/mef-for-beginner-ripetibile-metadata-parte-9.aspx stavo per postare questo ieri ma sono stato coinvolto in altre cose prima che potessi finire così godetevi i vostri punti ! – sohum

+0

Non è necessario rendere la classe ereditaria da "Attributo" piuttosto che da "ExportAttribute". Il punto di "MetadataAttributeAttribute" è brevità e concisione ;-).Il solo utilizzo di una vista metadata personalizzata e il lavoro manuale con gli array funziona per me. Non è ovvio dalla documentazione che 'AllowMultiple' fa sì che le voci dei metadati diventino array, quindi è strano ... – binki

Problemi correlati