Unity在调用堆栈中注入依赖关系

时间:2017-04-11 13:53:43

标签: c# dependency-injection unity-container

我正在试图掌握IoC容器(目前专门针对Unity),并且在预先注入所有依赖项的概念上有点挣扎。

我的问题特别与一个具有构造函数参数的类有关,该参数的值在我最初在容器中注册类型时是未知的。

这里有一个小片段,应该说明我在说什么。

class Class1
{
    IUnityContainer uContainer;

    public Class1()
    {
        uContainer = new UnityContainer();

        uContainer.RegisterType<IRepo, Repo>(new ContainerControlledLifetimeManager()));

        Class2 cls2 = uContainer.Resolve<Class2>();

        cls2.DoSomething();

    }
}

class Class2
{
    IRepo _repo;

    public Class2(IRepo p_repo)
    {
        _repo = p_repo;
    }

    public void DoSomething()
    {
        IType2 typ2 = new Type2(_repo.SomeDataRetrieved());

        Class3 cls3 = new Class3(_repo, typ2);
    }
}

class Class3
{
    IRepo _repo;
    IType2 _type2;

    public Class3(IRepo p_repo, IType2 p_type2)
    {
        _repo = p_repo;
        _type2 = p_type2;
    }
}

我可以在Class1中设置容器,并使用UnityContainer将Repo注入Class2。在Class2中,针对Repo的一些查找返回了Type2的实例,该实例只能在Class2中实例化。然后我需要将Repo传递给Class3以及Type2创建的新对象。

问题是双重的:

  1. 我无法在Class1中解析Class3,因为它只能在Class2中实例化。
  2. 我无法在容器中注册Type2,因为它实际上必须具有基于Class2中调用的输出的值(不是默认值),这与Container所在的范围不同并且执行了注册。
  3. 就目前而言,我可以使用容器将依赖项注入Class2,但是对于Class3,我需要创建新实例或使用2到3的构造函数注入,这让我想知道为什么我使用Container然后无论如何,我不得不求助于手动注射。

    那么,我如何在容器中注册Class3,以便在实例化时,我注入在开头的容器中注册的repo的单例以及在DoSomething中创建的Type2的实例。 / p>

    提前感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

我看到了关于你的方法的多个方面:

  1. 容器和注册应该在Class1之前进行。如果你只是把它写成一个例子,那么在你的实际代码中,它就在program中,或等效的,忽略了这个评论。
  2. 您应该使用Unity查看工厂。例如,在构造Class2时,您可以将Func<IType2, Class3>传递给它的构造函数,并从Class2中调用该工厂来获取Class3实例。这是一个例子:
  3. container.RegisterType<Func<Type2, Class3>>(
        new InjectionFactory(c =>
        new Func<Type2, Class3>(type2 =>
        c.Resolve<Class3>(
            new InjectionConstructor(
                new ResolvedParameter<IRepo>(),
                type2)))));
    

    注意:尚未测试那个代码,但我做了类似的事情。

答案 1 :(得分:0)

除了Tipx的答案,在进行依赖注入时,您不希望您的类直接创建其他类。

public void DoSomething()
{
    IType2 typ2 = new Type2(_repo.SomeDataRetrieved());
    Class3 cls3 = new Class3(_repo, typ2);
}

这会将class2Type2Class3联系起来,如果这三个关闭的话可能没问题,可以交换其中任何一个,但通常在某个时候你想换Type2代替OverchargedType2PlusType2Mock。这就是抽象工厂的用途:给Class2一些可以创建Type2的东西。

interface IType2Factory
{
     IType2 Create( Data theData );
}

class Type2Type2Factory : IType2Factory
{
     public IType2 Create( Data theData ) => new Type2( theData );
}

(如果Type2需要进一步的依赖关系,请参阅this answer

然后,将IType2Factory提交给Class2

class Class2
{
    private readonly IRepo _repo;
    private readonly IType2Factory _type2Factory;

    public Class2( IRepo repo, IType2Factory type2Factory )
    {
        _repo = repo;
        _type2Factory = type2Factory;
    }

    public void DoSomething()
    {
        var typ2 = _type2Factory.Create( _repo.SomeDataRetrieved() );
    }
}

当这一天到来且您需要OverchargedType2Plus时,请创建一个IType2Factory实施并对其进行注册,并观看Class2使用新的Type2变体,而不知道它存在,更不用说要求任何改变了。