Can dependency injection prevent a circular dependency?
Project#1 has some interfaces and classes that project#2 references.
Now I want to use the implementation of Project#2 in Project#1 but vs.net complains开发者_运维技巧 about a circular dependency.
If I was to use dependancy injection in Project#1 and bind to the implementation in Project#2 (since it adheres to the interface contract), will this work or I will still get the circular dependency error message at runtime?
You probably could solve this with DI, but you shouldn't.
If I understand correctly, you have something like this:
+ Assembly A + Assembly B | | +-- Interface IFoo +-- Class ConcreteFoo : IFoo | ^ +-- Class MyClass -->------->-------|
In other words, you're trying to get MyClass
to reference ConcreteFoo
, but you can't because assembly B
, which ConcreteFoo
resides in, already depends on IFoo
in A
.
This is a design error. If you declare the interface IFoo
in Assembly A
, but no concrete implementations, then any other interfaces/classes in assembly A
should only reference IFoo
, never a concrete class that implements it.
There are three ways to eliminate the circular dependency:
Make
MyClass
dependent onIFoo
instead ofConcreteFoo
. This is probably the best option if you can do it. If the issue is that you need a physical instance ofIFoo
for use inMyClass
and don't know where to get one from, then have it take anIFoo
in the constructor - let whoever usesMyClass
figure out whatIFoo
to use.Move the interfaces to their own assembly. This is still a reasonably good practice. Your design will look like this:
+ Assembly App + Assembly Interfaces + Assembly Concrete | | | | +-- Interface IFoo | | | \ | +-- Class MyClass | \------+-- Class ConcreteFoo | | | ^ +---- Member Foo ->--------------------->-------------------|
Move
MyClass
to its own assembly. Effectively your dependency tree will look the same as in #2 above, but if assemblyA
is much smaller thanB
then this would require less effort.
Hope that helps.
You can often resolve circular dependency issues with Dependency Injection (DI) using an Abstract Factory. See here for an example.
However, although you may be able to solve the problem with DI, it would be better to redesign the API to make the circular dependency go away.
You can often break a circular dependency by changing one of the ends from a query-based API to an event-based API.
As long as you are only using classes and interfaces from Project 1 in Project 1 code, you will be fine. (I'm assuming that the configuration for the dependency injection is done outside of the codebase of Project 1.)
But I have to also say, the presence of any circular dependency should lead you to question why it exists, and prompt thought on other ways to solve the problem that removes it.
精彩评论