jtk*_*rce 8 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");
_classB = value;
}
}
Run Code Online (Sandbox Code Playgroud)
另一个有ClassA的构造函数注入
class ClassB : IClassB
{
[InjectionConstructor]
public ClassB(IClassA classA)
{
_classA = classA;
}
}
Run Code Online (Sandbox Code Playgroud)
我无法在容器中正确解析这两个类.
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();
Run Code Online (Sandbox Code Playgroud)
这给了我一个堆栈溢出异常
我尝试了解决这个问题的不同顺序,但它似乎没有用.
我这是可行的还是我只是在浪费时间.这里究竟发生了什么.
Tyl*_*sen 17
我同意@Haney 这是一种代码味道,但技术上可行......
只需更改其中一个引用类型即可解析Lazy<T>
.然后它实际上不会解析该类型,直到使用它将打破无限递归循环.
即
class ClassB : IClassB
{
...
[InjectionConstructor]
public ClassB(Lazy<IClassA> classA)
{
_classA = classA;
}
}
Run Code Online (Sandbox Code Playgroud)
Han*_*ney 16
像Unity这样的DI框架工作的方式是,当你调用它们实例化一个类时,它们递归地实例化传递给该类的构造函数(或由属性设置)的所有类.这些类遵循相同的功能,因此您可以看到如何创建无限循环的递归.当Unity需要B时需要B和B时,它如何构建A?两者都无法建造.
在大多数DI框架中,您无法解析共同依赖的类.这是一个糟糕的设计模式AKA代码气味.在经典意义上,如果ClassA
需要了解ClassB
,并且ClassB
反过来需要了解ClassA
,那么现实是他们分享关注点并且应该合并为一个单独的类ClassC
.由于在这种情况下没有关注点分离,因此将它们分成两个单独的类,你什么都得不到.
像Unity这样的DI用于推广控制反转的模式,它只在类具有单向依赖性(不需要彼此了解)时才有效.