2012-03-29 21 views
9

'u kullanırken farklı kurgu parametrelerini bir parçaya aktarmak MEF kullanarak yapıcı parametre enjeksiyonu ile ilgili birçok soru olduğunu biliyorum, ancak benimki biraz farklı.MEF: CreationPolicy.NonShared

Bunu bilmek istiyorum ben PartCreationPolicy(CreationPolicy.NonShared) ve GetExportedValue kombinasyonunu kullanıyorum bir kısmının kurucusuna farklı parametre değerleri geçirmek için herhangi bir yolu var mı? Örneğin

:

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

ve başka bir yere ... Yukarıdaki örnekte

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

, bunu bir ChangeRejectedException neden olur ikinci kez çalışan olarak, yalnızca bir kez ComposeExportedValue kullanabilirsiniz.

Yani, sorularım şunlardır:

  1. yukarıdaki senaryoda SomeParam değerini değiştirmek için başka bir yolu her yeni örneği için, var mı? Aksi takdirde, başka bir DI çerçevesi kullanılmadan bunun başarılabileceği diğer yollar nelerdir? Akla gelen bir şey ise, GetExportedValue numaralı telefonu aramadan önce bir parametre değeri girdiğim ve daha sonra parçanın yapıcısındaki değeri düşürdüğüm System.Collections.Concurrent.ConcurrentQueue gibi bir şeyi açığa çıkarmak için bir hizmet oluşturmaktır. Ama bu bir hack ve aynı zamanda çözdüğünden daha fazla sorun yaratıyor.
  2. Yukarıdaki her iki sorunun cevabı hayırsa, bunu MEF ve diğer DI/IOC çerçevelerinin bir kombinasyonuyla gerçekleştirmenin başka yolları var mı?

Yardımlarınız için teşekkür ederiz. :)
Selamlar,
Yogesh Jagota

cevap

2

Yukarıdaki sorulara hem cevap hayır, o MEF ve diğer bazı DI/IOC çerçevesi kombinasyonu ile bunu yapmanın başka yolları da vardır edilirse?

Sanırım 1. ve 2. soruya verilen cevap gerçekten hayır.

Size daha ince taneli denetim ve integrates with MEF veren AutoFac'u denerim.

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

Ben arıyorum aşağıda gösterilen ancak 'RegisterComposablePartCatalog' kullanırken nasıl kayıt işleyebilir? AutoFac tarafından otomatik olarak yapıldığı için 'Register''ı kullanamıyorum. AutoFac'a, belirli bir dışa aktarmanın, [ImportingConstructor] 'ı kullanmadan temin ettiğim parametrelerle varsayılan olmayan bir kurucu kullanılarak başlatılması gerektiğini nasıl anlatabilirim? – Yogesh

+0

@Yogesh: AutoFac'a kayıtlı bazı bileşenlere sahip olabilirsiniz (ince taneli denetime gereksinim duyduğunuzda) ve MEF ile dışa aktarılanlar (eklentilerin dinamik keşfine ihtiyacınız olduğunda). Ancak, her ikisini de aynı bileşen için karıştıramazsınız. Diğer bir seçenek de AutoFac'a tamamen geçmek; Gerektiğinde MEF benzeri dinamik keşif yapmak için [Tarama] 'yı (http://code.google.com/p/autofac/wiki/Scanning) kullanabilirsiniz. –

+0

Aslında işe yaradı. Bunu yapmanın yolu, varolan bir kapsayıcıya yeni kayıtların eklenmesini sağlayan 'IContainer'ın' Update' yöntemini kullanmaktır. Teşekkürler. :) – Yogesh

1

bazı mantık bağlı olarak aynı arayüzünün farklı örneklerini kullanmak istiyorsanız (geçerlidir: Örneğin, Bar ve Baz örneklerini farklı parametre ile onların Foo örneğini almak, böylece böyle tescil kurmak için izin verir Stratejik model) ExportMetadata Attribute kullanmak için MEF bir şekilde. Örneğin Eğer IDbManager varsa ve siz iki uygulanmasını varsa biri Oracle ve One SQL sonra 1. meta

public interface IDbManagerMetadata 
{ 
    DataProvider DataProvider { get; } 
} 

2 tutacaktır meta arayüzü oluşturun söylüyorlar.Özellik sınıf oluşturma aşağıdaki

[MetadataAttribute] 
public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata 
{ 
    public DataProvider DataProvider { get; set; } 
} 
  1. strateji, örneğin

    halka enum DataProvider'ın { Oracle SQL, } [InheritedExport] ortak arabirim IDbManager { void Initialize(); }

    [InheritedExport (typeof (IDbManager))] genel sınıf DBManager: IDbManager { halka DBManager (DataProvider'ın providerType) { _providerType = providerType; }

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

    }

Ve İki farklı uygulamalar

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

    } 
} 

Ve

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

Ve yarattığımız Meta veri arabirimini kullanarak hangisinin kullanılacağına karar verebilir İlk adımda depoda olarak AutoFac/MEF Entegrasyon de

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