C# 统一分解循环依赖
在学习Unity(在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"
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;
}
}