2012-03-29 16 views
9

Wiem, że było wiele pytań dotyczących wprowadzania parametrów konstruktora za pomocą MEF, ale moje jest nieco inne.MEF: Przekazywanie różnych parametrów konstruktora do części przy użyciu CreationPolicy.NonShared

Chciałbym wiedzieć, czy istnieje sposób przekazania różnych wartości parametru do konstruktora części, gdy używam kombinacji PartCreationPolicy(CreationPolicy.NonShared) i GetExportedValue?

Na przykład:

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

i gdzieś indziej ...

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

W powyższym przykładzie, można użyć ComposeExportedValue tylko raz, jak działa to po raz drugi będzie powodować ChangeRejectedException.

Więc moje pytania to:

  1. Czy jest jakiś inny sposób, aby zmienić wartość SomeParam w powyższym scenariuszu dla każdej nowej instancji?
  2. Jeśli nie, jakie są inne sposoby, w jakie można to osiągnąć bez korzystania z innych struktur DI? Jedną z rzeczy, która przychodzi mi na myśl, jest utworzenie usługi, która wyeksponuje coś takiego, jak System.Collections.Concurrent.ConcurrentQueue, gdzie dodaję wartość parametru przed wywołaniem GetExportedValue, a następnie wycofam wartość w konstruktorze części. Ale to jest hack, a także stwarza więcej problemów niż rozwiązuje.
  3. Jeśli odpowiedź na oba powyższe pytania brzmi "nie", to czy istnieją inne sposoby osiągnięcia tego przy pomocy kombinacji MEF i innych frameworków DI/IOC?

Dzięki za pomoc. :) Pozdrawiam,

Yogesh Jagota

Odpowiedz

2

Jeśli odpowiedź na oba powyższe pytania brzmi nie, to czy są jakieś inne sposoby, aby tego dokonać za pomocą kombinacji MEF i innej ramy DI/IOC?

Myślę, że odpowiedź na pytanie 1 i 2 rzeczywiście nie jest.

Chciałbym wypróbować AutoFac, który daje dokładniejszą kontrolę ziarnistości i integrates with MEF. Na przykład, pozwala założyć rejestracje jak to tak, że Bar i Baz przypadki uzyskać ich wystąpienie Foo z innym parametrem:

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

Patrzę na AutoFac/MEF Integracji ale jak mogę obsługiwać rejestrację przy użyciu 'RegisterComposablePartCatalog'? Nie mogę użyć opcji "Zarejestruj", ponieważ jest ona automatycznie wykonywana przez AutoFac. Jak mogę powiedzieć AutoFac, że pewien eksport musi być utworzony za pomocą domyślnego konstruktora z parametrami, które dostarczam bez użycia '[ImportingConstructor]'? – Yogesh

+0

@ Yogesh: Niektóre komponenty mogą być zarejestrowane za pomocą AutoFac (gdy wymagana jest precyzyjna kontrola), a inne eksportowane za pomocą MEF (gdy potrzebujesz dynamicznego wykrywania wtyczek). Ale nie można mieszać obu dla tego samego komponentu. Inną opcją jest całkowite przejście do AutoFac; możesz użyć opcji [Skanowanie] (http://code.google.com/p/autofac/wiki/Scanning), aby w razie potrzeby uzyskać dynamiczne wykrywanie według MEF. –

+0

To zadziałało. Aby to zrobić, użyj metody 'Update' w' IContainer', która pozwala dodać nowe rejestracje do istniejącego kontenera. Dzięki. :) – Yogesh

1

Jeśli chcesz korzystać z różnych wystąpień samego interfejsu w zależności od pewnej logiki (zastosowanie wzór strategii) w MEF jednym ze sposobów wykorzystania atrybutu ExportMetadata. Na przykład, jeśli masz IDbManager a jeśli masz dwa wdrożenia to znaczy jeden Oracle i SQL One następnie 1. Tworzenie interfejsu metadanych, które będą trzymać metadane

public interface IDbManagerMetadata 
{ 
    DataProvider DataProvider { get; } 
} 

2.Tworzyć klasy atrybutów poniżej

[MetadataAttribute] 
public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata 
{ 
    public DataProvider DataProvider { get; set; } 
} 
  1. przykład strategii

    wyliczenia publicznego Dostawca danych { Oracle SQL, } [InheritedExport] interfejsu publicznej IDbManager { nieważne inicjalizacji(); }

    [InheritedExport (typeof (IDbManager))] Klasa publiczna DbManager: IDbManager { publicznego DbManager (Dostawca danych providerType) { _providerType = providerType; }

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

    }

i dwa różne implementacje

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

    } 
} 

I

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

I można zdecydować, który z nich korzystać za pomocą interfejsu Metadane stworzyliśmy w pierwszym etapie, jak pokazano poniżej w repozytorium

[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(); 
    } 
} 
Powiązane problemy