什么是循环依赖,我该如何解决?

What is a circular dependency and how can I solve it?

场景


我有一个解决方案,我有(超过)2 个项目。

第一个项目有对第二个项目的项目引用。第二个项目没有对第一个项目的引用。

好吧,在第一个项目中,我定义了一个可继承的 class 类型,我希望第二个项目中的一些 class 类型继承它。

问题


显然,如果我想继承第一个项目中定义的类型,在第二个项目中我需要添加对第一个项目的项目引用才能看到类型并继续。

问题是当我尝试添加项目引用时,我收到此错误消息:

问题


有人可以用其他简单的词来解释我(如果错误中暗示了代码,也可以用代码示例)什么是循环依赖?最重要的是:我能做些什么来解决它? (请在回答前阅读我研究的最后几句)。

研究


第一次听到“循环依赖”这个词;我读过来自 MSDN 的 this 文章,但我理解 nothing.

无论如何我看到了很多循环依赖的问题,比如this,从我在那个问题中看到的情况来看,循环依赖意味着两个项目不能它们之间同时引用,这两个项目中只有一个可以引用另一个; 并且所有回答该问题的人都说“重新设计是解决方案”或“循环依赖不是好的做法” ,但是,在我的情况下重新设计将意味着在两个项目中定义相同的类型,我认为这也不是好的做法,当然构建一个额外的 assembly/project 只是为了存储一个类型在两个项目中引用该程序集...我认为这是最糟糕的想法。

循环依赖是项目A依赖于项目B中的某些东西,而项目B又依赖于项目A中的某些东西。这意味着要编译项目A,你必须先编译项目B,但你不能像B那样做需要编译 A。这就是循环依赖导致的问题。

如果您对已经构建的项目引入循环依赖,则很难发现它,因为标准构建选项不会删除现有的目标文件,因此您可以先构建 A(或 B) .只有当您尝试在以前从未构建过解决方案的另一台机器上或者您进行清理和构建时,您才会发现它。

re-designing in my case will mean define the same type in both projects, which I don't think that could be good practices neither.

在这种情况下,您需要创建第三个项目 "C",其中包含 A 和 B 都依赖的 类,因此它们不再相互依赖。您可能只需将 类 分开,这样就可以在不创建第三个项目的情况下对依赖项进行排序。

什么是依赖?

为了理解什么是循环依赖,最好理解什么是依赖以及它对编译器意味着什么。

假设您有一个项目,并且在 class 中定义了以下内容:

Public Class MyClass
    'Some code here
    Private MyString As String
    'Some code there
End Class

编译您的项目时,编译器运行将字符串class 转换为在名为System.dll 的DLL 文件中定义的字符串class。然后它将 link 该 DLL 添加到您的项目中,因此在 运行 时,在对字符串进行定义或操作时,将加载 System.dll 以执行这些操作。

现在,假设您在 class 中有以下定义

'Some code here
Private MyObjet as CustomClass1
'Some code there

假设 CustomClass1 在您的另一个项目中定义,名为 Project2.DLL:

Public Class CustomClass1
    'Your custom class code
End Class

所以当编译你的第一个项目时,编译器会将 运行 定义为 CustomClass1 定义,它知道它位于 Project2.dll 中,因此会先编译 Project2,以便能够在您的第一个项目中添加该引用。

这就是依赖,它是有层次的,必须有一个起点。甚至字符串 class 也依赖于其他 classes,最后,它们都依赖字节或位来完成这项工作,因为这是计算机唯一可以做的事情,玩 10.

所以圆形部分

因此,如果您在 Project2 中有一个 link 对您的第一个项目的引用(字段定义或类似内容),会发生什么?

  • 编译器读取您的第一个项目,然后 运行s 进入 CustomClass1
  • 然后它尝试编译 Project2,因为 CustomClass1 在那里定义
  • 然后 运行s 到第一个项目中定义的 class
  • 它会尝试编译您的第一个项目,以便 link 它成为第二个
  • 然后 运行s 到 CustomClass1
  • 然后它尝试编译 Project2
  • 我猜你明白了...

所以在某些时候编译器会显示错误,说它无法编译,因为它不理解你正在尝试做什么...

是的,电脑就是这么笨。

如何解决?

解决这类问题有时很困难,但基本思想是建立一个层次结构,将基础class(不需要依赖项)放在一起,然后在它们之上构建.

把所有相互依赖的 class 放在一起,它们形成一个层,用于您在应用程序中尝试做的事情。

不要使用项目作为参考,而是使用该项目的构建 DLL 进行参考。如果您在解决方案的每个模块中都这样做,您就可以解决它。 如果您有两个名为 'main' 和 'sub' 的项目 然后在主工程中添加子工程的DLL作为引用文件,同时在子工程中添加主工程的DLL作为引用..

据我所知,修复 CD 的最简单方法是创建接口项目,并让 CD 中涉及的项目引用接口项目,而不是相互引用。 有点乱,但它有效。