2012-03-29 14 views
9

Sé que ha habido muchas preguntas con respecto a la inyección de parámetros de constructor usando MEF, pero la mía es un poco diferente.MEF: Pasar parámetros de constructor diferentes a una parte al usar CreationPolicy.NonShared

Quiero saber que hay alguna forma de pasar diferentes valores de parámetros al constructor de una pieza cuando estoy usando la combinación de PartCreationPolicy(CreationPolicy.NonShared) y GetExportedValue?

Por ejemplo:

[PartCreationPolicy(CreationPolicy.NonShared)] 
[Export] 
public partial class Foo 
{ 
    [ImportingConstructor] 
    public Foo([Import("SomeParam")]object parameter) 
    { 
     ... 
    } 
} 

y en otro lugar ...

container.ComposeExportedValue("SomeParam", "Some value..."); 
var instance = container.GetExportedValue<Foo>(); 

En el ejemplo anterior, puedo usar ComposeExportedValue sólo una vez, como correr una segunda vez causará una ChangeRejectedException.

Por lo tanto, mis preguntas son:

  1. ¿Hay alguna otra manera de cambiar el valor de SomeParam en el escenario anterior, para cada nueva instancia?
  2. Si no, ¿cuáles son las otras formas en que esto se puede lograr sin utilizar ningún otro marco DI? Una cosa que me viene a la mente es crear un servicio para exponer algo como System.Collections.Concurrent.ConcurrentQueue donde pongo en cola un valor de parámetro antes de llamar al GetExportedValue y luego dequeue el valor en el constructor de la pieza. Pero eso es un truco y también crea más problemas de los que resuelve.
  3. Si la respuesta a ambas preguntas es no, ¿hay alguna otra forma de lograr esto con una combinación de MEF y algún otro marco DI/IOC?

Gracias por cualquier ayuda. :) Saludos,

Yogesh JAGOTA

Respuesta

2

Si la respuesta a las dos preguntas es no, entonces ¿Hay otras maneras de lograr esto con una combinación de MEF y algún otro marco DI/COI?

Creo que la respuesta a la pregunta 1 y 2 es, de hecho, no.

Me gustaría probar AutoFac que le da un control de grano más fino y integrates with MEF. Por ejemplo, se le permite configurar registros de este tipo de manera que Bar y Baz casos obtienen su ejemplo Foo con un parámetro diferente:

builder.Register(c => new Bar(new Foo(param)); 
builder.Register(c => new Baz(new Foo(param2)); 
+0

estoy mirando autofac/Integración MEF pero ¿cómo puedo manejar el registro cuando se utiliza 'RegisterComposablePartCatalog'? No puedo usar 'Registrarse' aquí ya que AutoFac lo hace automáticamente. ¿Cómo puedo decirle a AutoFac que una determinada exportación necesita ser instanciada usando un constructor no predeterminado con los parámetros que proporciono sin usar el '[ImportingConstructor]'? – Yogesh

+0

@Yogesh: Puede tener algunos componentes registrados con AutoFac (cuando necesita un control detallado) y otros exportados con MEF (cuando necesita un descubrimiento dinámico de complementos). Pero no puedes mezclar ambos para el mismo componente. Otra opción es cambiar a AutoFac por completo; puede usar [Escaneo] (http://code.google.com/p/autofac/wiki/Scanning) para obtener un descubrimiento dinámico similar a MEF donde sea necesario. –

+0

Realmente funcionó. La forma de hacerlo es usar el método 'Update' de' IContainer' que permite agregar nuevos registros a un contenedor existente. Gracias. :) – Yogesh

1

Si desea utilizar diferentes instancias de una misma interfaz, dependiendo de cierta lógica (aplicar patrón de estrategia) en MEF una forma de usar ExportMetadata Attribute. Por ejemplo, si tiene IDbManager y si tiene dos ejecución de la misma decir una Oracle y SQL Uno continuación 1. Crear interfaz de metadatos que contendrá los metadatos

public interface IDbManagerMetadata 
{ 
    DataProvider DataProvider { get; } 
} 

2.Crear clase Atributo de la siguiente manera

[MetadataAttribute] 
public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata 
{ 
    public DataProvider DataProvider { get; set; } 
} 
  1. ejemplo Estrategia

    enumeración pública DataProvider { Oracle, SQL, } [InheritedExport] interfaz pública IDbManager { vacío Initialize(); }

    [InheritedExport (typeof (IDbManager))] DBManager clase pública: IDbManager { DBManager público (DataProvider ProviderType) { _providerType = ProviderType; }

    public void Initialize() 
    { 
        Console.WriteLine("provider : {0}", _providerType); 
    } 
    
    public DataProvider _providerType { get; set; } 
    

    }

y dos diferentes implementaciones

[Export(typeof(IDbManager))] 
[DbManagerMetadata(DataProvider = DataProvider.Oracle)] 
public sealed class OracleDataProvider : DbManager 
{ 
    public OracleDataProvider():base(DataProvider.Oracle) 
    { 

    } 
} 

Y

[Export(typeof(IDbManager))] 
[DbManagerMetadata(DataProvider = DataProvider.Sql)] 
public sealed class SqlDataProvider : DbManager 
{ 
    public SqlDataProvider() 
     : base(DataProvider.Sql) 
    { 
    } 
} 

y usted puede decidir cuál usar mediante el uso de la interfaz de metadatos que hemos creado en el primer paso como en el repositorio se muestra a continuación

[Export] 
public class Repository 
{ 
    private IDbManager _dbManager; 

    private readonly IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> DbManagers; 

    [ImportingConstructor] 
    public Repository([ImportMany(typeof(IDbManager))]IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> dbManagers) 
    { 
     this.DbManagers = dbManagers; 
     var _dbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value; 
    } 

    public void Execute() 
    { 
     var oracleDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value; 

     oracleDbManager.Initialize(); 

     var sqlDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Sql).Value; 

     sqlDbManager.Initialize(); 
    } 
} 
Cuestiones relacionadas