2012-03-29 6 views
9

So che ci sono state molte domande sull'iniezione dei parametri del costruttore tramite MEF, ma il mio è un po 'diverso.MEF: passaggio di diversi parametri del costruttore a una parte quando si utilizza CreationPolicy.NonShared

Desidero sapere che esiste un modo per passare valori di parametri diversi al costruttore di una parte quando utilizzo la combinazione di PartCreationPolicy(CreationPolicy.NonShared) e GetExportedValue?

Ad esempio:

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

e da qualche altra parte ...

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

Nell'esempio di cui sopra, posso usare ComposeExportedValue solo una volta, come l'esecuzione di una seconda volta causerà un ChangeRejectedException.

Quindi, le mie domande sono:

  1. C'è un altro modo per cambiare il valore della SomeParam nello scenario precedente, per ogni nuova istanza?
  2. In caso contrario, quali sono gli altri modi in cui questo può essere realizzato senza utilizzare altri framework DI? Una cosa che viene in mente è creare un servizio per esporre qualcosa come System.Collections.Concurrent.ConcurrentQueue dove accodare un valore di parametro prima di chiamare GetExportedValue e quindi dequotare il valore nel costruttore della parte. Ma questo è un trucco e crea anche più problemi di quanti ne risolva.
  3. Se la risposta a entrambe le domande sopra è no, allora ci sono altri modi per ottenere questo risultato con una combinazione di MEF e qualche altro framework DI/IOC?

Grazie per qualsiasi aiuto. :)
Saluti,
Yogesh Jagota

risposta

2

Se la risposta ad entrambe queste domande è no, allora ci sono altri modi per ottenere questo con una combinazione di MEF e qualche altro quadro DI/CIO?

Penso che la risposta alle domande 1 e 2 sia effettivamente no.

Vorrei provare AutoFac che ti dà più controllo a grana fine e integrates with MEF. Ad esempio, consente di impostare le registrazioni di questo tipo in modo che Bar e Baz casi ottengono il loro esempio Foo con un parametro diverso:

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

sto guardando autofac/MEF integrazione ma come posso gestire la registrazione quando si utilizza 'RegisterComposablePartCatalog'? Non riesco ad usare 'Register' qui come è stato fatto automaticamente da AutoFac. Come posso dire ad AutoFac che una certa esportazione deve essere istanziata usando un costruttore non predefinito con i parametri che fornisco senza usare '[ImportingConstructor]'? – Yogesh

+0

@ Yogesh: è possibile avere alcuni componenti registrati con AutoFac (quando è necessario il controllo a grana fine) e altri esportati con MEF (quando è necessario il rilevamento dinamico dei plug-in). Ma non è possibile mescolare entrambi per lo stesso componente. Un'altra opzione è quella di passare completamente ad AutoFac; puoi utilizzare [Scansione] (http://code.google.com/p/autofac/wiki/Scanning) per ottenere una scoperta dinamica simile a MEF dove necessario. –

+0

Ha funzionato davvero. Il modo per farlo è utilizzare il metodo 'Update' di' IContainer' che consente di aggiungere nuove registrazioni a un contenitore esistente. Grazie. :) – Yogesh

1

Se si desidera utilizzare diverse istanze della stessa interfaccia a seconda una logica (a modello di strategia) in MEF un modo per utilizzare l'Attributo ExportMetadata. Per esempio se avete IDbManager e se si dispone di due attuazione è dire un'Oracle e Sql Uno poi 1. Creare un'interfaccia metadati che conterrà metadati

public interface IDbManagerMetadata 
{ 
    DataProvider DataProvider { get; } 
} 

2.Creare classe Attribute, come di seguito

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

    enum pubblico FornitoreDati { Oracle, Sql, } [InheritedExport] interfaccia pubblica IDbManager { vuoto Initialize(); }

    [InheritedExport (typeof (IDbManager))] classe DBManager pubblico: IDbManager { pubblico DBManager (FornitoreDati ProviderType) { _providerType = ProviderType; }

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

    }

e due diverse implementazioni

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

    } 
} 

E

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

e si può decidere quale usare tramite interfaccia metadati abbiamo creato nel primo passaggio come nel repository Di seguito riportiamo

[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(); 
    } 
} 
Problemi correlati