Как Microsoft создавала сборки с циклическими ссылками?


в .NET BCL есть циклические ссылки между:

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

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

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

8 99

8 ответов:

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

Они сначала компилируют систему.Конфигурация.dll файлы, без необходимости обращения к системе.XML.файл DLL. После этого они компилируют систему.XML.dll обычным способом. Теперь приходит волшебство. Они перекомпилируют систему.конфигурация.dll, с частью, нуждающейся в ссылке на систему.XML.файл DLL. Теперь есть успешная компиляция с круговой ссылкой.

In коротко:

  • это компилируется без кода нуждающийся в B и ссылка на B.
  • B компилируется.
  • в перекомпилируется.

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

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

Это можно сделать так, как описано в Dykam, но Visual Studio блокирует это.

вам придется использовать компилятор командной строки csc.ехе напрямую.

  1. csc / target: библиотека ClassA.cs

  2. csc / target: библиотека ClassB.ЗС /ссылка:класса.dll

  3. csc / target: библиотека ClassA.cs ClassC.КС /ссылка:то.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. открыть visual studio
  2. создать 2 проекта библиотеки классов "ClassLibrary1" & "ClassLibrary2".
  3. построить
  4. из ClassLibrary1 добавьте ссылку на ClassLibrary2, перейдя в библиотеку dll, созданную на Шаге 3.
  5. из ClassLibrary2 добавьте ссылку на ClassLibrary1, перейдя в библиотеку dll, созданную на Шаге 3.
  6. построить опять же (Примечание: Если вы вносите изменения в оба проекта, вам нужно будет построить дважды, чтобы сделать обе ссылки "свежими")

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

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

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

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

  1. Ссылка A без каких-либо ссылок на B.
  2. Ссылка B С ссылки на А.
  3. Ссылка A, добавление в ссылки на B.

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

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

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