Depedency injection: injecting partially-initialized objects

拜拜、爱过 提交于 2020-01-03 10:42:06

问题


This question is about Unity Container but I guess it is applicable to any dependency container.

I have two classes with circular dependencies:

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

class SecondClass
{
    public readonly FirstClass First;

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

Technically it's possible to instantiate and correctly inject dependencies for both of them if treat them as singletons:

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

When I try to do the same with Unity, I get StackOverflowException:

var container = new UnityContainer();
container.RegisterType<FirstClass>(new ContainerControlledLifetimeManager());
container.RegisterType<SecondClass>(new ContainerControlledLifetimeManager());

var first = container.Resolve<FirstClass>(); // StackOverflowException here!
var second = container.Resolve<SecondClass>(); // StackOverflowException here too!

I understand that Unity tries to protect me from using partially initialized objects but I want to have this protection as an option, not an obligation.

Question: is current behavior disabable?


回答1:


I think you cannot use circular dependencies with unity at all.

See: http://msdn.microsoft.com/en-us/library/cc440934.aspx




回答2:


One way round this would be to use lazy loading for the dependencies on one of the classes:

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



回答3:


you can use RegisterInstance instead of RegisterType to achieve your goal. It will behave just like singleton - will use the same instance every time Resolve is invoked. Take a look at this example:

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

Cheers,

Pavel



来源:https://stackoverflow.com/questions/1377608/depedency-injection-injecting-partially-initialized-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!