2012-06-11 7 views
5

No entiendo muy bien MEF, así que espero que sea una solución simple de cómo creo que funciona.MEF GetExports <T, TMetaDataView> no devuelve nada con AllowMultiple = True

Estoy tratando de usar MEF para obtener información sobre una clase y cómo se debe utilizar. Estoy usando las opciones de metadatos para tratar de lograr esto. Mis interfaces y atributo se ve así:

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 clase que está decorado con el atributo tiene el siguiente aspecto:

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

El método que está tratando de utilizar la importación se parece a esto:

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

En mi caso myExports siempre está vacío. En mi CompositionContainer, tengo una parte en mi catálogo que tiene dos ExportDefinitions, ambos con el siguiente ContractName: "MyNamespace.IMyInterface". El Metadata también se carga correctamente según mis exportaciones.

Si elimino el setter AllowMultiple y solo incluyo un atributo exportado, la variable myExports ahora tiene la única exportación con sus metadatos cargados.

¿Qué estoy haciendo mal?

EDIT: Si uso flexible de tipos de metadatos, mi exportación es repente satisfechos:

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

Cualquier idea por qué?

Respuesta

9

Se sabe que MEF tiene algunos problemas cuando se trata de AllowMultiple = true. Para una explicación completa, por ejemplo, puede mirar here, de todos modos se deriva del hecho de que los metadatos se guardan en un diccionario donde los valores son matrices cuando AllowMultiple es verdadero, y tal cosa no se puede mapear en su IMyInterfaceInfo.

Esta es la solución alternativa que uso. En primer lugar el atributo debe derivar de atributo, no desde 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; } 
} 

Esto significa que la clase exportado debe tener 3 atributos, un estandar para exportación y atributos de su encargo:

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

Entonces usted tiene para definir una vista para los metadatos que serán importados. Esto tiene que tener un constructor que tome IDictionary como parámetro. Algo como esto:

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

Ahora usted debería ser capaz de llamar con éxito

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

Sí, eso es lo que terminé haciendo, después de leer el siguiente artículo: http://blogs.microsoft.co. il/blogs/bnaya/archive/2010/01/29/mef-for-beginner-repeatable-metadata-part-9.aspx Iba a publicar esto ayer, pero me metí en otras cosas antes de poder terminar, así que disfruta tus puntos ! – sohum

+0

No es necesario hacer que la clase herede de 'Attribute' en lugar de' ExportAttribute'. El punto de 'MetadataAttributeAttribute' es brevedad y concisión ;-).Solo el uso de una vista de metadatos personalizada y el tratamiento manual de las matrices me funciona. No es obvio a partir de la documentación que 'AllowMultiple' hace que las entradas de metadatos se conviertan en matrices, tan raro ... – binki

Cuestiones relacionadas