Как Microsoft создала сборки, имеющие круговые ссылки?

В .NET BCL есть круглые ссылки между:

  • System.dll и System.Xml.dll
  • System.dll и System.Configuration.dll
  • System.Xml.dll и System.Configuration.dll

Вот скриншот из .NET Reflector, который показывает, что я имею в виду:

enter image description here

Как Microsoft создала эти сборки, для меня загадка. Требуется ли для этого специальный процесс компиляции? Я предполагаю, что здесь происходит что-то интересное.

Ответ 1

Я могу только сказать, как это делает Mono Project. Теорема довольно проста, хотя и дает кодовый беспорядок.

Сначала они компилируют System.Configuration.dll без части, требующей ссылки на System.Xml.dll. После этого они компилируют System.Xml.dll обычным способом. Теперь приходит волшебство. Они перекомпилируют System.configuration.dll с частью, требующей ссылки на System.Xml.dll. Теперь есть успешная компиляция с круговой ссылкой.

Короче:

  • А скомпилирован без кода необходимо B и ссылку на B.
  • B скомпилирован.
  • A перекомпилируется.

Ответ 2

RBarryYoung и Dykam находятся на чем-то. Microsoft использует внутренний инструмент, который использует ILDASM для демонтажа сборок, разбивает все внутренние/частные вещи и тела методов и снова переписывает IL (используя ILASM) в так называемую сборку "обезвоженные сборки" или метаданные. Это делается каждый раз, когда изменяется общий интерфейс сборки.

Во время сборки вместо обычных используются метаданные. Таким образом, цикл нарушается.

Ответ 3

Это можно сделать так, как описал 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 {
    }
}

Ответ 4

Его довольно легко сделать в Visual Studio, если вы не используете ссылки на проект... Попробуйте следующее:

  • Открыть визуальную студию
  • Создайте проекты библиотеки классов "ClassLibrary1" и "ClassLibrary2".
  • Построить
  • В ClassLibrary1 добавьте ссылку на ClassLibrary2, просмотрев DLL, созданную на шаге 3.
  • В ClassLibrary2 добавьте ссылку на ClassLibrary1, просмотрев DLL, созданную на шаге 3.
  • Сборка еще раз (обратите внимание: если вы вносите изменения в оба проекта, вам нужно будет построить дважды, чтобы обе ссылки были "свежими" ).

Так вот как вы это делаете. Но серьезно... Разве вы никогда не делаете это в реальном проекте! Если вы это сделаете, Санта не принесет вам подарков в этом году.

Ответ 5

Я думаю, это можно сделать, начав с ациклического набора сборок и используя ILMerge, чтобы затем объединить меньшие сборки в логически связанные группы.

Ответ 6

Ну, я никогда не делал этого в Windows, но я сделал это на многих средах компиляции-ссылок-rtl, которые служили в качестве практических предшественников. То, что вы делаете, сначала делает заглушки "цели" без перекрестных ссылок, затем ссылки, затем добавляет циклические ссылки, а затем повторно соединяет. Обычно линкеры не заботятся о циклических ссылках или последующих цепях ref, они только заботятся о возможности разрешить каждую ссылку на нее.

Итак, если у вас есть две библиотеки, A и B, которые должны ссылаться друг на друга, попробуйте что-то вроде этого:

  • Ссылка A без ссылок на B.
  • Ссылка B с ссылками на A.
  • Ссылка A, добавление ссылок на B.

Dykam делает хорошую точку, он компилируется, а не связан в .Net, но принцип остается тем же: сделайте свои источники с перекрестными ссылками с их экспортированными точками входа, но при этом все, кроме одного, имеют свои собственные ссылки на другие прорезали. Постройте их так. Затем развяжите внешние ссылки и перестройте их. Это должно работать даже без каких-либо специальных инструментов. Фактически, этот подход работал на каждой операционной системе, которую я когда-либо пробовал (около 6 из них). Хотя, очевидно, что-то, что автоматизирует его, будет большой помощью.

Ответ 7

Одним из возможных подходов является использование условной компиляции (#if) для первой компиляции System.dll, которая не зависит от этих других сборок, затем компилирует другие сборки и, наконец, перекомпилирует System.dll для включения частей в зависимости от на Xml и Configuration.

Ответ 8

Технически, возможно, что они не были составлены вообще и собраны вручную. В конце концов, это библиотеки низкого уровня.