Как Microsoft создала сборки, которые имеют циклические ссылки? - PullRequest
103 голосов
/ 22 августа 2009

В .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 создала эти сборки, для меня загадка. Требуется ли для этого специальный процесс компиляции? Я думаю, что здесь происходит что-то интересное.

Ответы [ 8 ]

56 голосов
/ 22 августа 2009

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

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

Короче говоря:

  • A компилируется без кода нуждающийся в B и ссылка на B.
  • B скомпилировано.
  • A перекомпилируется.
35 голосов
/ 22 августа 2009

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

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

26 голосов
/ 22 августа 2009

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

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

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

  2. csc / target: библиотека ClassB.cs /reference:ClassA.dll

  3. csc / target: библиотека 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 {
    }
}
17 голосов
/ 24 августа 2009

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

  1. Открытая визуальная студия
  2. Создание 2 проектов библиотеки классов "ClassLibrary1" и "ClassLibrary2".
  3. Сложение
  4. В ClassLibrary1 добавьте ссылку на ClassLibrary2, перейдя к dll, созданному на шаге 3.
  5. В ClassLibrary2 добавьте ссылку на ClassLibrary1, перейдя к dll, созданному на шаге 3.
  6. Повторная сборка (Примечание: если вы вносите изменения в оба проекта, вам нужно будет собрать дважды, чтобы обе ссылки были «свежими»)

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

6 голосов
/ 22 августа 2009

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

4 голосов
/ 22 августа 2009

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

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

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

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

1 голос
/ 22 августа 2009

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

0 голосов
/ 06 октября 2009

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

...