While learning Unity (DI framework in C#
) I came across a situation where one class has a setter injection of ClassB
class ClassA : IClassA
{
[Dependency]
public IClassB ClassB
{
get { return _classB; }
set
{
if (value == null) throw new ArgumentNullException("value");
_classB = value;
}
}
and the other has a constructor injection of the ClassA
class ClassB : IClassB
{
[InjectionConstructor]
public ClassB(IClassA classA)
{
_classA = classA;
}
}
I am not able to resolve both the classes correctly within the container.
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();
This gives me a stack overflow exception
I tried different ordering of resolving this but it doesn't seem to work.
I this doable or am I just wasting my time.
What is exactly happening here ?
To resolve circular dependencies: Then there are three strategies you can use: Look for small pieces of code that can be moved from one project to the other. Look for code that both libraries depend on and move that code into a new shared library. Combine projectA and projectB into one library.
But circular dependencies in software are solvable because the dependencies are always self-imposed by the developers. To break the circle, all you have to do is break one of the links. One option might simply be to come up with another way to produce one of the dependencies, in order to bootstrap the process.
Circular dependencies can be introduced when implementing callback functionality. This can be avoided by applying design patterns like the observer pattern.
A simple way to break the cycle is by telling Spring to initialize one of the beans lazily. So, instead of fully initializing the bean, it will create a proxy to inject it into the other bean. The injected bean will only be fully created when it's first needed.
The way that DI frameworks like Unity work is, when you call them to instantiate a class, they recursively instantiate all classes being passed into the constructor (or set by property) of that class. Those classes follow the same function, and so you can see how you've created an infinite loop of recursion. How does Unity construct A when it needs B and B when it needs A? Neither can ever be constructed.
You can't resolve co-dependent classes in most DI frameworks. This is a bad design pattern AKA a code smell. In the classical sense, if ClassA
needs to know about ClassB
, and ClassB
in return needs to know about ClassA
, then the reality is that they share concerns and should be combined into a single class ClassC
. You gain nothing by having them in 2 separate classes since there is no separation of concerns in this case.
DI such as Unity is used to promote the pattern of Inversion of Control, which works only when classes have a one-way dependency (don't need to know about each other).
I agree with @Haney that this is a code smell, but it is technically possible...
Just change one of the referenced types to be resolved via Lazy<T>
. Then it does not actually resolve that type until it is used which will break out of the infinite recursion loop.
i.e.
class ClassB : IClassB
{
...
[InjectionConstructor]
public ClassB(Lazy<IClassA> classA)
{
_classA = classA;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With