Yapıcı parametrelerini Unity'nin Resolve () yöntemine iletebilir miyim?


92

Bağımlılık ekleme için Microsoft Unity kullanıyorum ve bunun gibi bir şey yapmak istiyorum:

IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);

RepositoryAve RepositoryBher ikisinin de IDataContextparametre alan bir kurucu var ve Unity'nin depoyu ilettiğim bağlamla başlatmasını istiyorum. Ayrıca Unity'ye IDataContextkayıtlı olmadığını da unutmayın (3 örnek istemiyorum IDataContext).

Yanıtlar:


71

Bugün itibariyle şu işlevi eklediler:

Buradaki en son düşüşte:

http://unity.codeplex.com/SourceControl/changeset/view/33899

Burada tartışma:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

Misal:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"



2
"'Microsoft.Practices.Unity.ParameterOverrides' sınıfının tür parametreleri yoktur". Unity 3.5 kullanıyorum; bu kod yalnızca Unity'nin eski bir sürümü için geçerli mi?
Thomas Levesque

Benim için çalışıyor. Not: Sınıfınızın "ad" parametresi ve "adres" parametresi olan parametrize bir kurucusu olmalıdır. Foo(string name, int address) { ... }
adun

Unity 2.1 Kullanımı: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2 sent>

Ya daha sonra bağlamdan fazlasını ya da daha fazlasını gerektiren farklı bir hizmet kullanmaya karar verirseniz?

Yapıcı parametreleri ve IoC ile ilgili sorun, parametrelerin, hizmet arayüzünün tanımladığı sözleşmenin bir parçası olmanın aksine, sonuçta kullanılan somut türe bağlı olmasıdır.

Benim önerim, ya bağlamı da çözmeniz ve Unity'nin sizin için bunun 3 örneğini inşa etmekten kaçınmanız gerektiğine inanıyorum ya da nesneyi inşa etmek için size bir yol olan bir fabrika hizmeti düşünmelisiniz.

Örneğin, daha sonra hiç geleneksel bir veritabanına dayanmayan, bunun yerine test için sahte veriler üretmek için bir XML dosyası kullanan bir havuz oluşturmaya karar verirseniz ne olur? XML içeriğini o kurucuya beslemeye nasıl devam edersiniz?

IoC, argümanların tipini ve anlamını somut türlere bağlayarak kod çözme temeline dayanır, ayrıştırmayı gerçekten doğru yapmadınız, hala bir bağımlılık var.

"Bu kod, bu arabirimi uyguladığı sürece, muhtemelen herhangi bir depo türüyle konuşabilir .... Oh, ve bir veri bağlamı kullanıyor".

Şimdi, diğer IoC konteynerlerinin bunun için desteği olduğunu biliyorum ve benim de ilk versiyonumda vardı, ancak bence bu, çözüm adımına ait değil.

</ 2 sent>


3
Söylediğiniz noktayı görüyorum ve size katılıyorum, ancak yine de RepositoryA ve RepositoryB örneklerinin RepositoryC'den farklı olması gereken aynı IDataContext'e sahip olmasına ihtiyacım var. Ayrıca IRepositoryA ve IRepositoryB'nin IDataContext için bir özelliği olduğunu unutmayın. Örnek kodu biraz güncelleyeceğim.
NotDan

2
Harika nokta. Kurucuya bir string parametresi eklemek üzereydim, ancak bu noktayı inceledikten sonra, onu tam gelişmiş bir nesne yapmaya karar verdim. Bu noktada yalnızca dizeden oluşur, ancak ona nasıl daha kullanışlı özellikler ekleyebileceğimi şimdiden görebiliyorum
Santosh Benjamin

9

Teşekkürler çocuklar ... benimki "Exist" yazısına benziyor. Aşağıya bakınız:

        IUnityContainer container = new UnityContainer();
        container.LoadConfiguration();

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

5

Kapsayıcıda önceden kaydedilmiş bir Nesnenin bir örneğini almak için ResolvedParameter <T> ("name") içindeki Enjeksiyon Mimarinize bağlı olarak InjectionConstructor / InjectionProperty / InjectionMethod'u kullanabilirsiniz.

Sizin durumunuzda bu Nesnenin bir Ad ile kaydedilmesi gerekir ve aynı şekilde LifeTimeManager olarak ContainerControlledLifeTimeManager () 'a ihtiyacınız vardır.

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");

  var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));

  var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));

4
Bu koddan emin misin? Derlemez ... Resolvebir koleksiyon alır ResolverOverrideve InjectionConstructorbir ResolverOverride.
Thomas Levesque

Evet, yanlış görünüyor. Gerçi birlik bu şekilde tasarlamış olmalıydı. Parametre adı değişirse her şey kesilir
Frank Q.

3

Çok kısa cevap: hayır. Unity'nin şu anda, bulabildiğim sabit veya enjekte edilmemiş parametreleri kurucuya geçirme yolu yoktur. IMHO, eksik olduğu en büyük şey, ancak bence ihmalden ziyade tasarım gereği.

Jeff Fritz'in belirttiği gibi, teoride hangi bağlam örneğinin çeşitli türlere enjekte edileceğini bilen özel bir yaşam boyu yöneticisi yaratabilirsiniz, ancak bu, ilk başta Unity veya DI kullanma amacını ortadan kaldıran bir kodlama düzeyidir.

Tam DI'dan küçük bir adım atabilir ve depo uygulamalarınızı kendi veri bağlamlarını oluşturmaktan sorumlu yapabilirsiniz. Bağlam örneği yine de konteynerden çözülebilir, ancak hangisinin kullanılacağına karar verme mantığının deponun uygulamasına girmesi gerekir. Kesinlikle o kadar saf değil, ama problemden kurtulacaktır.


1

Kullanabileceğiniz başka bir alternatif (bunun iyi bir uygulama olup olmadığını gerçekten bilmiyorum) iki kapsayıcı oluşturmak ve her biri için bir örnek kaydetmek:

IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context


//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance

umarım bu da yardımcı olur


0

NotDan, lassevk'e yaptığınız yorumlarda kendi sorunuzu yanıtlamış olabilirsiniz.

İlk olarak, Unity'nin oluşturduğu IDataContext örneğinin yaşam döngüsünü ve sayısını yönetmek için bir LifetimeManager kullanacağım.
http://msdn.microsoft.com/en-us/library/cc440953.aspx

ContainerControlledLifetimeManagerNesne size ihtiyacınız olan örnek yönetimini verecek gibi görünüyor . Bu LifetimeManager yerinde olduğunda, Unity, bir IDataContext bağımlılığı gerektiren tüm nesnelere aynı IDataContext örneğini eklemelidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.