依赖注入可以防止循环依赖吗?

时间:2010-01-12 22:46:34

标签: c# dependency-injection assemblies circular-dependency

项目#1有一些接口和类,用于投射#2引用。

现在我想在Project#1中使用Project#2的实现,但vs.net抱怨循环依赖。

如果我要在Project#1中使用依赖注入并绑定到Project#2中的实现(因为它遵守接口契约),这是否可行或者我仍会在运行时获得循环依赖性错误消息?< / p>

3 个答案:

答案 0 :(得分:15)

你可能可以用DI来解决这个问题,但你不应该

如果我理解正确,你会有这样的事情:

  + Assembly A           + Assembly B
  |                      |
  +-- Interface IFoo     +-- Class ConcreteFoo : IFoo
  |                                   ^
  +-- Class MyClass -->------->-------|

换句话说,您试图让MyClass引用ConcreteFoo,但您不能,因为B所在的汇编ConcreteFoo已经取决于在IFoo的{​​{1}}上。

这是一个设计错误。如果在Assembly A中声明接口IFoo,但没有具体实现,那么程序集A中的任何其他接口/类应引用{{1} },从不实现它的具体类。

有三种方法可以消除循环依赖:

  1. A取决于IFoo而不是MyClass。如果你能做到这一点,这可能是最好的选择。如果问题是您需要在IFoo中使用ConcreteFoo的物理实例并且不知道从哪里获取,请在构造函数中使用IFoo - 让使用MyClass的任何人都会找出IFoo要使用的内容。

  2. 将接口移动到自己的程序集。这仍然是一个相当不错的做法。您的设计将如下所示:

      + Assembly App       + Assembly Interfaces      + Assembly Concrete
      |                    |                          |
      |                    +-- Interface IFoo         |
      |                    |                  \       |
      +-- Class MyClass    |                   \------+-- Class ConcreteFoo
      |                    |                          |           ^
      +---- Member Foo ->--------------------->-------------------|
    
  3. MyClass移至自己的程序集。有效地,您的依赖关系树看起来与上面的#2相同,但如果汇编IFoo远小于MyClass,那么这将需要更少的工作量。

  4. 希望有所帮助。

答案 1 :(得分:8)

您通常可以使用抽象工厂解决依赖注入(DI)的循环依赖性问题。请参阅here for an example

但是,尽管您可以通过DI解决问题,但最好重新设计API以使循环依赖性消失。

您通常可以通过将基于查询的API中的一端更改为基于事件的 API来打破循环依赖。

答案 2 :(得分:1)

只要你在Project 1代码中只使用Project 1中的类和接口,你就可以了。 (我假设依赖注入的配置是在Project 1的代码库之外完成的。)

但是我还要说,任何循环依赖的存在都会引导你质疑它为什么存在,并提示其他方法来解决消除它的问题。