2010-01-05 12 views
36

Estoy intentando descubrir el atributo de inyección de constructor de MEF. No tengo idea de cómo le digo que cargue los parámetros del constructor.MEF Constructor Injection

Esta es la propiedad que estoy tratando de cargar

[ImportMany(typeof(BUsers))] 
public IEnumerable<BUsers> LoadBUsers { get; set; } 

Aquí está el código que estoy usando para importar las asambleas.

try 
{ 
    var catalog = new AggregateCatalog(); 
    catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); 
    catalog.Catalogs.Add(new DirectoryCatalog("DI")); 
    var container = new CompositionContainer(catalog); 
    container.ComposeParts(this); 
} 

Aquí es la clase que estoy tratando de cargar

[Serializable] 
[Export(typeof(BUsers))] 
public class EditProfile : BUsers 
{ 
    [ImportingConstructor] 
    public EditProfile(string Method, string Version) 
    {    
     Version = "2"; 
     Action = "Edit"; 
     TypeName = "EditProfile"; 
    } 

Respuesta

53

Cuando se utiliza el atributo ImportingConstructor, los parámetros de las importaciones constructor convertido. Por defecto, lo que está importando (el nombre del contrato) se basa en el tipo de parámetro o propiedad en el que está importando. Entonces, en este caso, el tipo de contrato para ambas importaciones es cadena, y no hay diferencia real entre el primero y el segundo parámetro.

Parece que está intentando usar importaciones para proporcionar valores de configuración, que no es necesariamente para lo que fue diseñado. Para conseguir que haga lo que quiere, debe reemplazar el nombre de contrato para cada uno de los parámetros, así:

[ImportingConstructor] 
public EditProfile([Import("Method")] string Method, [Import("Version")] string Version) 
{ } 

entonces usted necesita para las exportaciones Método y la versión de su contenedor. Una forma de hacer esto es sólo para añadirlas directamente:

var container = new CompositionContainer(catalog); 
container.ComposeExportedValue("Method", "MethodValue"); 
container.ComposeExportedValue("Version", "2.0"); 
container.ComposeParts(this); 

(Tenga en cuenta que ComposeExportedValue es en realidad un método de extensión definida en la clase AttributedModelServices estática.)

Si desea leer estos valores de una configuración archivo de algún tipo, puede crear su propio proveedor de exportación que lea la configuración y proporcione los valores que contiene como exportaciones al contenedor.

Una forma alternativa de manejar esto sería importar una interfaz que proporcione acceso a los valores de configuración por nombre y obtener los valores que necesita del cuerpo del constructor.

+0

Acabo de descargar la nueva en CodePlex. El método de ComposeExportedValue() no está en la clase de CompositionContainer. ¿Dónde está? –

+0

Creo que encontré el método. Está en la clase de AttributedModelServices, donde el método se define como método extendido para clasificar CompositionContainer. –

+1

@ David.Chu.ca Sí, ComposeExportedValue es un método de extensión en la clase AttributedModelServices. –

23

Me gusta la solución de Daniel; sin embargo, solo una cosa que veo es el estrecho acoplamiento de nombres de parámetros entre el actor (que crea CompopositionContrainer()) y Exportar parte con [ImportingConstructor] para CTOR personalizado. Por ejemplo, "Método" tiene dos correspondencias en ambos lugares. Hace difícil mantener la parte Exportar si el actor y la parte Exportar están en proyectos diferenciados.

Si es posible, agregaría el segundo CTOR a la clase de pieza Exportar. Por ejemplo:

[Export(typeof(BUsers))] 
public class EditProfile : BUsers 
{ 
    [ImportingConstructor] 
    public EditProfile(EditProfileParameters ctorPars) 
    : this(ctorPars.Method, ctorPars.Version) {} 

    public EditProfile(string Method, string Version) 
    { 
     Version = "2"; 
     Action = "Edit"; 
     TypeName = "EditProfile"; 
    } 

La clase de EditProfileParameters debe ser sencillo: dos propiedades del método y la Versión:

[Export] 
public class EditProfileParameters{ 
    public string Method { get; set; } 
    public string Version { get; set; } 
} 

El punto clave consiste en añadir el atributo de exportación a la clase. Entonces MEF debería poder asignar esta clase al parámetro de CTOR de EditProfile.

Aquí es ejemplo para añadir la parte de exportación de contenedores:

var container = new CompositionContainer(catalog); 
var instance1 = new EditProfileParameters(); 
// set property values from config or other resources 
container.ComposeExportedValue(instance1); 
container.ComposeParts(this); 
0

Aunque tarde al juego, aquí hay otro enfoque que aprovecha una característica menos conocida de MEF: Las exportaciones de Propiedad

public class ObjectMother 
{ 
    [Export] 
    public static EditProfile DefaultEditProfile 
    { 
     get 
     { 
      var method = ConfigurationManager.AppSettings["method"]; 
      var version = ConfigurationManager.AppSettings["version"]; 

      return new EditProfile(method,version); 
     } 
    } 
} 

No se requieren usos para ObjectMother para que esto funcione, y no se requieren atributos en EditProfile.

+0

Buena característica, pero ¿qué pasa si 'EditProfile' contiene alguna importación? En ese caso, debe llamar a 'SatisfyImportsOnce' en el contenedor. Eso duele. Actualmente no tengo una solución real para ese problema. –

+0

En este caso, estamos construyendo una fábrica que ejemplifica manualmente su EditProfile. Si EditProfile requiere dependencias adicionales en el constructor, siempre puede traer esas dependencias a la fábrica a través de un ImportingConstructor. Debo señalar que si agrega dependencias adicionales a EditProfile, esta es la única referencia en su aplicación a este constructor y obtendrá errores de tiempo de compilación. Es un comercio justo, en mi humilde opinión. – bryanbcook