在.NET BCL中,以下之间存在循环引用:
System.dll
和System.Xml.dll
System.dll
和System.Configuration.dll
System.Xml.dll
和System.Configuration.dll
这是.NET Reflector的屏幕截图,显示了我的意思:
微软如何创建这些程序集对我来说还是一个谜。是否需要特殊的编译过程才能允许这样做?我想象这里会发生一些有趣的事情。
在.NET BCL中,以下之间存在循环引用:
System.dll
和 System.Xml.dll
System.dll
和 System.Configuration.dll
System.Xml.dll
和 System.Configuration.dll
这是.NET Reflector的屏幕截图,显示了我的意思:
微软如何创建这些程序集对我来说还是一个谜。是否需要特殊的编译过程才能允许这样做?我想象这里会发生一些有趣的事情。
Answers:
我只能说出Mono项目是如何做到的。该定理很简单,尽管它使代码混乱。
他们首先编译System.Configuration.dll,而无需引用System.Xml.dll。之后,他们以正常方式编译System.Xml.dll。现在来了魔术。他们重新编译System.configuration.dll,其中一部分需要引用System.Xml.dll。现在,使用循环引用成功进行了编译。
简而言之:
RBarryYoung和Dykam陷入了困境。Microsoft使用内部工具,该工具使用ILDASM分解程序集,剥离所有内部/私有内容和方法体,然后再次将IL重新编译(使用ILASM)成“脱水程序集”或元数据程序集。每次更改装配的公共接口时都将执行此操作。
在构建期间,将使用元数据程序集代替实际的元数据程序集。这样循环就坏了。
可以按照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中就很容易做到这一点...尝试以下操作:
这就是您的操作方式。但是认真的……您永远不会在一个真实的项目中做到这一点!如果您愿意,圣诞老人今年不会为您带来任何礼物。
好吧,我从来没有在Windows上做到过,但是我已经在许多compile-link-rtl环境中做到了这一点,这些环境是它的实际产生者。您要做的是首先使存根为“目标”而没有交叉引用,然后链接,然后添加循环引用,然后重新链接。链接程序通常不关心循环引用或跟随引用链,它们只关心能够自己解析每个引用。
因此,如果您有两个需要相互引用的库A和B,请尝试如下操作:
Dykam很好说,它是可编译的,而不是.Net中的链接,但是原理仍然是相同的:使交叉引用的源具有其导出的入口点,但除了其中一个以外的所有源均具有自己对其他源的引用出来。这样构建它们。然后,取消外部引用的存根并重建它们。即使没有任何特殊工具,该方法也应能起作用,实际上,这种方法已经在我尝试过的每个操作系统上起作用(大约有6个)。尽管显然可以实现自动化的东西还是有很大帮助的。
一种可能的方法是使用条件编译(#if)首先编译不依赖于那些其他程序集的System.dll,然后编译其他程序集,最后重新编译System.dll以包括取决于Xml和组态。