Microsoft如何创build具有循环引用的程序集?
在.NET BCL中有以下几种循环引用:
-
System.dll
和System.Xml.dll
-
System.dll
和System.Configuration.dll
-
System.Xml.dll
和System.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。
-
csc / target:library ClassA.cs
-
csc / target:library ClassB.cs /reference:ClassA.dll
-
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中很容易做到这一点…试试这个:
- 打开视觉工作室
- 创build2个类库项目“ClassLibrary1”和“ClassLibrary2”。
- build立
- 从ClassLibrary1中,通过浏览到步骤3中创build的dll,添加对ClassLibrary2的引用。
- 从ClassLibrary2中,通过浏览到步骤3中创build的dll,添加对ClassLibrary1的引用。
- 重新构build(注意:如果在两个项目中进行更改,则需要重新构build两次以使两个参考都为“新鲜”)
所以这是你如何做到的。 但认真的…你不是真的在一个真正的项目中做! 如果你这样做,圣诞老人今年不会给你带来任何礼物。
我想这可以通过从一组非循环的程序集开始,然后使用ILMerge将较小的程序集合成逻辑相关的组来完成。
那么,我从来没有在Windows上做过这个,但是我已经在很多编译链接的RTL环境中做过实际的祖先。 你所做的是首先做存根“目标”没有交叉引用然后链接,然后添加循环引用,然后重新链接。 连接器通常不关心循环引用或跟随引用链,他们只关心能够自己解决每个引用。
所以,如果你有两个库,需要相互引用的A和B,试试这样的:
- 链接A没有任何参考B.
- 链接B 与裁判A.
- 链接A,在参考文献中joinB.
Dykam提供了一个很好的观点,它是编译的,而不是链接在.Net中,但是原理保持不变:使用交叉引用的源代码,使用它们的导出入口点,但除了其中一个引用外,出。 像那样构build它们。 然后,取消外部引用并重build它们。 即使没有任何特殊的工具,这也应该可以工作,事实上,这种方法已经在我尝试过的每一个操作系统上工作过了(其中大约6个)。 显然,自动化的东西将是一个很大的帮助。
一种可能的方法是使用条件编译(#if)首先编译不依赖于其他程序集的System.dll,然后编译其他程序集,最后重新编译System.dll以包含依赖于Xml的部分组态。
从技术上讲,这些可能根本不是编译的,而是手工组装的。 毕竟,这些都是低级库。