C# 统一分解循环依赖

C# 统一分解循环依赖,c#,unity-container,C#,Unity Container,在学习Unity(在C#中的DI框架)时,我遇到了这样一种情况:一个类有ClassB的setter注入 class ClassA : IClassA { [Dependency] public IClassB ClassB { get { return _classB; } set { if (value == null) throw new ArgumentNullException("value"

在学习Unity(在
C#
中的DI框架)时,我遇到了这样一种情况:一个类有
ClassB
的setter注入

class ClassA : IClassA
{
    [Dependency]
    public IClassB ClassB
    {
        get { return _classB; }
        set
        {
            if (value == null) throw new ArgumentNullException("value");
            _classB = value;
        }
    }
另一个具有
ClassA

class ClassB : IClassB
{
    [InjectionConstructor]
    public ClassB(IClassA classA)
    {
        _classA = classA;
    }
}
我无法在容器中正确解析这两个类

var container = new UnityContainer();
container.RegisterType<IClassB, ClassB>();
container.RegisterType<IClassA, ClassA>();
IClassA classA = new ClassA();
var instance = container.Resolve<ClassA>();
instance.DoSomethingFromClassB();

log.Info("Constructor Injection");
var instanceB = container.Resolve<ClassB>();
instanceB.DoSomethingFromClassA();
var container=newunitycontainer();
container.RegisterType();
container.RegisterType();
IClassA classA=新classA();
var instance=container.Resolve();
DoSomethingFromClassB();
log.Info(“构造函数注入”);
var instanceB=container.Resolve();
instanceB.DoSomethingFromClassA();
这给了我一个堆栈溢出异常

我尝试了解决这个问题的不同顺序,但似乎不起作用

我认为这是可行的,或者我只是在浪费时间


这里到底发生了什么?

像Unity这样的DI框架的工作方式是,当您调用它们来实例化一个类时,它们递归地实例化传递给该类的构造函数(或属性集)的所有类。这些类遵循相同的函数,因此您可以看到如何创建无限递归循环。当统一需要B时,它如何构造A,当统一需要A时,它如何构造B?两者都无法构建

在大多数DI框架中,您无法解析相互依赖的类这是一种糟糕的设计模式,又称代码气味。在经典意义上,如果
ClassA
需要了解
ClassB
,而
ClassB
反过来需要了解
ClassA
,那么现实是它们都有共同的顾虑,应该合并成一个类
ClassC
。如果将它们放在两个单独的类中,您将一无所获,因为在本例中没有分离关注点


像Unity这样的DI被用来促进控制反转的模式,这种模式只有在类具有单向依赖性(不需要相互了解)时才起作用。

我同意@Haney的观点,这是一种代码气味,但在技术上是可能的

只需通过
Lazy
更改要解析的引用类型之一。然后,在使用它之前,它实际上不会解析该类型,这将打破无限递归循环

i、 e

B类:IClassB
{
...
[注入构造函数]
公共类B(惰性类A)
{
_classA=classA;
}
}

是的,您可以使用C解析A和B。这也是一种常见的模式—使用“容器”或“编写器”保存两个相关的类。不过,不要太在意流行语/行话谢谢我们正在重构以使用构造函数注入,这揭示了一些循环依赖。我们最终将此作为一个临时解决方案,这样我们就可以检查我们所拥有的,并作为一项单独的任务清理循环依赖关系。作为对那些来到这里的人的鼓励。我会说,是的,有时这是一种代码气味,但有时这是代码库感到成长痛苦的结果。只要你试着避开财产注入,我就不会太担心了。祝你好运!
class ClassB : IClassB
{
...
    [InjectionConstructor]
    public ClassB(Lazy<IClassA> classA)
    {
        _classA = classA;
    }
}