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

时间:2009-08-22 17:26:07

标签: .net assemblies circular-reference base-class-library

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

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

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

enter image description here

微软如何创建这些程序集对我来说是一个谜。是否需要特殊的编译过程才允许这样做?我想这里有一些有趣的东西。

8 个答案:

答案 0 :(得分:56)

我只能告诉Mono Project如何做到这一点。这个定理很简单,虽然它给代码搞乱了。

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

简而言之:

  • 在没有代码的情况下编译A. 需要B和B的引用。
  • B已编译。
  • A被重新编译。

答案 1 :(得分:35)

RBarryYoung和Dykam正在努力。 Microsoft使用内部工具使用ILDASM来反汇编程序集,删除所有内部/私有内容和方法主体,并再次将IL重新编译(使用ILASM)到所谓的“脱水程序集”或元数据程序集中。每次更改装配的公共接口时都会这样做。

在构建期间,使用元数据程序集而不是实际的元数据程序集。这样循环就被打破了。

答案 2 :(得分:26)

它可以按照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

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

答案 3 :(得分:17)

只要你不使用项目引用,它在Visual Studio中就很容易了...试试这个:

  1. 打开visual studio
  2. 创建2个类库项目“ClassLibrary1”& “ClassLibrary2”。
  3. 构建
  4. 从ClassLibrary1中,通过浏览到步骤3中创建的dll,添加对ClassLibrary2的引用。
  5. 从ClassLibrary2中,通过浏览到步骤3中创建的dll,添加对ClassLibrary1的引用。
  6. 再次构建(注意:如果您在两个项目中进行更改,则需要构建两次以使两个引用都“新鲜”)。
  7. 所以你就是这样做的。但是说真的......难道你不是在真正的项目中做到这一点!如果你这样做,圣诞老人今年不会带给你任何礼物。

答案 4 :(得分:6)

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

答案 5 :(得分:4)

好吧,我从来没有在Windows上完成它,但我已经在很多编译链接-rtl环境中完成了它,它们是它的实际祖先。你要做的是首先制作存根“目标”而不用交叉引用然后链接,然后添加循环引用,然后重新链接。链接器通常不关心循环引用或跟随引用链,它们只关心能够自己解析每个引用。

因此,如果您有两个需要互相引用的库A和B,请尝试以下方法:

  1. 没有任何参考的链接A到B.
  2. 使用链接B 参考A。
  3. 链接A,将引用添加到B。

  4. Dykam提出了一个很好的观点,它是编译,而不是链接.Net,但原则保持不变:使用导出的入口点制作交叉引用的源,但除了其中一个源外,其他所有源都有自己的引用其他人潦倒。像那样构建它们。然后,取消存储外部引用并重建它们。即使没有任何特殊工具,这应该可以工作,事实上,这种方法已经适用于我曾经尝试过的每个操作系统(大约6个)。虽然显然可以自动化的东西会有很大的帮助。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

从技术上讲,它们可能根本没有编译,而是手工组装。毕竟,这些是低级库。