Microsoft如何创build具有循环引用的程序集?

在.NET BCL中有以下几种循环引用:

  • System.dllSystem.Xml.dll
  • System.dllSystem.Configuration.dll
  • System.Xml.dllSystem.Configuration.dll

下面是.NET Reflector的截图,显示了我的意思:

在这里输入图像说明

微软如何创build这些程序集对我来说是个谜。 是否需要一个特殊的编译过程? 我想象一些有趣的事情在这里发生。

我只能告诉Mono项目如何做到这一点。 这个定理非常简单,尽pipe它给代码弄得一团糟。

他们首先编译System.Configuration.dll,而不需要引用System.Xml.dll的部分。 之后,他们以正常的方式编译System.Xml.dll。 现在来了魔法。 他们重新编译System.configuration.dll,需要引用System.Xml.dll的部分。 现在有一个成功的循环引用编译。

简而言之:

  • A编译时没有需要B的代码和对B的引用。
  • B被编译。
  • A被重新编译。

RBarryYoung和Dykam的东西。 Microsoft使用内部工具使用ILDASM来反汇编程序集,去除所有内部/私有的东西和方法体,并重新编译IL(使用ILASM)到所谓的“脱水程序集”或元数据程序集中。 每当组装的公共接口被改变时都会这样做。

在构build期间,使用元数据程序集而不是真正的程序集。 这种方式周期被打破。

这可以通过Dykam描述的方式完成,但是Visual Studio会阻止你这样做。

您将不得不直接使用命令行编译器csc.exe。

  1. csc / target:library ClassA.cs

  2. csc / target:library ClassB.cs /reference:ClassA.dll

  3. csc / target:library ClassA.cs ClassC.cs /reference:ClassB.dll

 //ClassA.cs namespace CircularA { public class ClassA { } } //ClassB.cs using CircularA; namespace CircularB { public class ClassB : ClassA { } } //ClassC.cs namespace CircularA { class ClassC : ClassB { } } 

只要你不使用项目引用,在Visual Studio中很容易做到这一点…试试这个:

  1. 打开视觉工作室
  2. 创build2个类库项目“ClassLibrary1”和“ClassLibrary2”。
  3. build立
  4. 从ClassLibrary1中,通过浏览到步骤3中创build的dll,添加对ClassLibrary2的引用。
  5. 从ClassLibrary2中,通过浏览到步骤3中创build的dll,添加对ClassLibrary1的引用。
  6. 重新构build(注意:如果在两个项目中进行更改,则需要重新构build两次以使两个参考都为“新鲜”)

所以这是你如何做到的。 但认真的…你不是真的在一个真正的项目中做! 如果你这样做,圣诞老人今年不会给你带来任何礼物。

我想这可以通过从一组非循环的程序集开始,然后使用ILMerge将较小的程序集合成逻辑相关的组来完成。

那么,我从来没有在Windows上做过这个,但是我已经在很多编译链接的RTL环境中做过实际的祖先。 你所做的是首先做存根“目标”没有交叉引用然后链接,然后添加循环引用,然后重新链接。 连接器通常不关心循环引用或跟随引用链,他们只关心能够自己解决每个引用。

所以,如果你有两个库,需要相互引用的A和B,试试这样的:

  1. 链接A没有任何参考B.
  2. 链接B 裁判A.
  3. 链接A,在参考文献中joinB.

Dykam提供了一个很好的观点,它是编译的,而不是链接在.Net中,但是原理保持不变:使用交叉引用的源代码,使用它们的导出入口点,但除了其中一个引用外,出。 像那样构build它们。 然后,取消外部引用并重build它们。 即使没有任何特殊的工具,这也应该可以工作,事实上,这种方法已经在我尝试过的每一个操作系统上工作过了(其中大约6个)。 显然,自动化的东西将是一个很大的帮助。

一种可能的方法是使用条件编译(#if)首先编译不依赖于其他程序集的System.dll,然后编译其他程序集,最后重新编译System.dll以包含依赖于Xml的部分组态。

从技术上讲,这些可能根本不是编译的,而是手工组装的。 毕竟,这些都是低级库。