6

Bu soru Unity Container hakkındadır ancak sanırım herhangi bir bağımlılık kabına uygulanabilir.Depresyon enjeksiyonu: kısmi başlatılmış nesneler enjekte etme

ben dairesel bağımlılıkları ile iki sınıf vardır:

class FirstClass 
{ 
    [Dependency] 
    public SecondClass Second { get; set; } 
} 

class SecondClass 
{ 
    public readonly FirstClass First; 

    public SecondClass(FirstClass first) 
    { 
     First = first; 
    } 
} 

Teknik singletons olarak ele eğer örneğini ve doğru olarak ikisi için de bağımlılıkları enjekte etmek mümkündür:

var firstObj = new FirstClass(); 
var secondObj = new SecondClass(firstObj); 
firstObj.Second = secondObj; 

ben yapmaya çalışacağım Birlik ile aynı, StackOverflowException alır:

Birliğin beni kısmen başlatılmış nesneleri kullanmamdan korumaya çalıştığını biliyorum ama bu korumayı bir zorunluluk değil bir seçenek olarak kullanmak istiyorum.

Soru: Mevcut davranış engelli mi?

cevap

5

Dairesel bağımlılıkları bir arada kullanamazsınız.

bakınız: Bu sınıflardan birinde bağımlılıkları için tembel yükleme kullanmak olacaktır http://msdn.microsoft.com/en-us/library/cc440934.aspx

+0

ama elle yapabilirsiniz: Bu örnekte bir göz atın. Verdiğiniz MDSN bağlantısından, benim durumum için aşağıdakilerden hiçbiri doğru değil: - Yapıcı parametrelerinde birbirini referans alan yapıcı enjeksiyonuyla oluşturulan nesneler - Bir sınıf örneğinin iletildiği, yapıcı enjeksiyonu yoluyla oluşturulan nesneler kendi kurucusuna parametre - Birbirine referans veren yöntem çağrısı enjeksiyonu yoluyla oluşturulan OO'lar - Birbirine referans veren özellik (ayarlayıcı) enjeksiyonuyla oluşturulan OO'lar –

+0

Sorun, birkaç saniyede "FirstClass" bağımlılık nesnesi olmadan yaşar. bu gerçekten geçerli olmadığı anlamına gelir. Bütün bunlar temel olarak, nesnelerin inşa edildiğinde ne yaptığına bağlıdır, eğer ikinci sınıfınız, ilk nesneyi çağırmaya çalışırsa, ilk olanın bağımlı nesneyi kullanılabilir olmasını beklerse, o zaman başarısız olur. Bunun gibi dairesel zincirler çeşitli nedenlerden dolayı sorunludur, bu yüzden mümkünse kaçınmaya çalışmalısınız. –

+0

Özellikle nesnelerimi elle oluşturabildiğim hesaba katılarak StackOverflowException yerine NRE almayı tercih ederim. –

2

Tek yönlü yuvarlak:

[TestFixture] 
public class CircularUnityTest 
{ 
    IUnityContainer container; 

    [SetUp] 
    public void SetUp() 
    { 
     container = new UnityContainer(); 
     container.RegisterType(typeof(ILazy<>), typeof(Lazy<>)); 
     container.RegisterType<FirstClass>(new ContainerControlledLifetimeManager()); 
     container.RegisterType<SecondClass>(new ContainerControlledLifetimeManager()); 
    } 

    [Test] 
    public void CanResolveFirstClass() 
    { 
     var first = container.Resolve<FirstClass>(); 
     Assert.IsNotNull(first); 
    } 

    [Test] 
    public void CanResolveSecondClass() 
    { 
     var second = container.Resolve<SecondClass>(); 
     Assert.IsNotNull(second); 
    } 

    [Test] 
    public void CanGetFirstFromSecond() 
    { 
     var second = container.Resolve<SecondClass>(); 
     Assert.IsNotNull(second.First); 
    } 
} 

class FirstClass 
{ 
    [Dependency] 
    public SecondClass Second { get; set; } 
} 

class SecondClass 
{ 
    private readonly ILazy<FirstClass> lazyFirst; 

    public FirstClass First { get { return lazyFirst.Resolve(); } } 

    public SecondClass(ILazy<FirstClass> lazyFirst) 
    { 
     this.lazyFirst = lazyFirst; 
    } 
} 

public interface ILazy<T> 
{ 
    T Resolve(); 
} 

public class Lazy<T> : ILazy<T> 
{ 
    IUnityContainer container; 

    public Lazy(IUnityContainer container) 
    { 
     this.container = container; 
    } 

    public T Resolve() 
    { 
     return container.Resolve<T>(); 
    } 
} 
+2

Bu ilginç bir fikir! Bu konuda sevmediğim şey, derslerimin Unity hakkında bilmesi ve basit ve açık referanslar yerine Lazy 'u kullanmam gerekmesi. –

+0

Bu iki yıl sonra adım attığımız için üzgünüm, ama ... Bu tam olarak aradığım şey ama benim için çalışmıyor. "ILazy " yi çözemeyeceğini söyleyen bir bağımlılık çözümü istisnası alıyorum. Yukarıdaki kod hala çalışıyor mu, yoksa farklı bir yaklaşım gerektiren Birlikte değişiklikler var mı? – Samo

+0

@Samo evet hala benim için Unity 2'ye karşı çalışıyor.Unity'nin hangi sürümünü kullanıyorsunuz? Kodumu tam olarak kopyaladın mı? Çalışması için ILazy açık jenerik kayıt olmanız gerekir. (nb Bunu daha önce yazdım. NET 4, biraz farklı olan kendi Lazy tipi ile geldi) –

1

Eğer hedefe ulaşmak için yerine RegisterType arasında RegisterInstance kullanabilirsiniz. Tekil gibi davranacak - Resolve çağrıldığında her zaman aynı örneği kullanacaktır. Ben sınıfları örneğini olamayacağını Birlik sevmiyorum

class FirstClass 
{ 
    [Dependency] 
    public SecondClass Second { get; set; } 
} 

class SecondClass 
{ 
    public readonly FirstClass First; 

    public SecondClass(FirstClass first) 
    { 
     First = first; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IUnityContainer container = new UnityContainer(); 
     var firstObj = new FirstClass(); 

     var secondObj = new SecondClass(firstObj); 
     firstObj.Second = secondObj; 

     // Register instance instead of type!!! 
     container.RegisterInstance<FirstClass>(firstObj); 
     container.RegisterType<SecondClass>(); 

     var first = container.Resolve<FirstClass>(); 
     var second = container.Resolve<SecondClass>(); 
    } 
} 

Şerefe,

Pavel

+1

Her iki nesneyi de el ile oluşturuyorsunuz. Benim sorduğum şey, benim yapmak istemediğim şey bu. Benim asıl amacım Unity'yi benim için yapıyor. Sadece iki değil düzinelerce bileşeni olacak gerçek dünya uygulamasında çok çirkin olacak.Örnekte de * ilk.Second * ve * second.First * aynı olmayacak! –

İlgili konular