Можно ли включить циклические зависимости в Visual Studio на уровне сборки? Возможны ли взаимозависимые сборки?

Возможно, это звучит глупо, но я все равно дам ему шанс.

Итак, в Visual Studio у вас не может быть двух проектов X и Y таких, что X ссылки Y и Y ссылаются на X.

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

Но действительно ли невозможно скомпилировать два проекта, которые взаимозависимы таким образом? Мне кажется, что это должно быть возможно, поскольку (по моему мнению, может быть, я совершенно не знаю об этом) наличие двух взаимозависимых сборок действительно не так сильно отличается от наличия двух взаимозависимых классов - случая, который правовой и может быть скомпилирован.

Было бы разумно, если бы вы сказали: "две сборки не могут зависеть друг от друга, потому что компилятор не может скомпилировать один перед другим"; за исключением того, что, похоже, вы можете сделать тот же аргумент для двух классов в рамках одной и той же сборки, и, очевидно, компилятор может справиться с этим сценарием просто отлично.

В основном причина, по которой я прошу, заключается не в том, что у меня есть какое-то отчаянное желание делать эту вещь, которую я знаю, как правило, вообще не рекомендуется. В частности, мне интересно, потому что было бы неплохо, если бы у меня было два проекта - например, MyProjectCS и MyProjectVB - которые существовали в основном как две взаимозависимые части одного элемента и были только отдельными, поскольку некоторые части были написаны на С# и другие части были написаны на VB.NET.

Итак, мой вопрос (yikes, три раза):

  • Возможно ли включить это поведение (например, в Visual Studio или в другом месте)?
  • Если это невозможно в любой среде IDE, возможно ли это, по крайней мере, теоретически, или могут существовать взаимозависимые сборки?
  • Если это даже теоретически невозможно, почему бы и нет? Другими словами, как взаимозависимые сборки отличаются от взаимозависимого кода внутри одной сборки?

Ответы

Ответ 1

Я не знаю, как это сделать в среде IDE; однако его можно построить с помощью процесса сборки.

Вам понадобится:

  • Сборка A
  • Сборка B
  • Сборка заготовки B

где Stub Assembly B содержит общедоступные классы и общедоступные методы сборки B и той же AssemblyInfo. * и ссылается на один и тот же открытый ключ.

Порядок сборки:

  • Скомпилировать сборку заглушек B
  • Скопируйте узел B штампа в выходной каталог сборки B
  • Сборка сборки A
  • Сборка сборки B

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

Примечание:

ilasm может скомпилировать истинные взаимно-рекурсивные сборки, так как он может разрешать типы, которые не существуют во время компиляции.

ДАЛЕЕ:

aspnet_compiler, похоже, может смешивать разные языки в одном проекте (кто знает, как это сделать).

Ответ 2

Несмотря на то, что сборки mscorlib.dll и System.dll взаимозависимы, я бы посоветовал никогда не иметь двух сборок, зависящих друг от друга.

Что касается циклов зависимостей между позами типа пространств имен, я бы посоветовал использовать NDepend для обнаружения и избежания циклов зависимостей.

alt text

Выдержка из статьи (я написал): Зависит от компонентов компонента для получения чистой архитектуры

Циклы зависимостей между компонентами приводят к тому, что обычно называют спагетти-кодом или запутанным кодом. Если компонент A зависит от B, который зависит от C, который зависит от A, компонент A не может быть разработан и испытан независимо от B и C. A, B и C образуют неделимую единицу, своего рода суперкомпонент. Этот суперкомпонент имеет более высокую стоимость, чем сумма затрат по сравнению с A, B и C из-за неэффективности масштабного явления (хорошо документировано в Software Estimation: Demystifying the Black Art от Steve McConnell). В основном, это означает, что стоимость разработки неделимой части кода возрастает экспоненциально.

Это говорит о том, что разработка и поддержание 1000 LOC (Lines Of Code), вероятно, будет стоить в три-четыре раза больше, чем разработка и поддержание 500 LOC, если только он не может быть разделен на два независимых куска по 500 LOC каждый. Следовательно, сравнение с спагетти, которое описывает запутанный код, который не поддерживается. Чтобы рационализировать архитектуру, необходимо убедиться, что между компонентами нет циклов зависимостей, но также убедитесь, что размер каждого компонента является приемлемым (от 500 до 1000 LOC).

Ответ 3

Я не знаю, как это будет работать в VB, но теоретически должно быть возможно использовать какой-то заполнитель, указывающий на другой (генерирующий незаконный код) для компиляции одного из них, а затем использовать его для компиляции другого, а затем перекомпилировать первый.

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

- Хотя обычно это делается путем отключения функций, которые еще не существуют

Ответ 4

Если вы создаете с помощью инструментов командной строки, вы можете иметь сборку, содержащую много модулей. Каждый модуль может быть скомпилирован с помощью другого компилятора. Модули могут иметь круговые зависимости между ними.

Однако я не ожидаю, что зрительная студия никогда не увидит этого.


Есть и трюк, который вы можете сделать, и это позволит компоновщику перенаправить запрос типа с одной сборки на другую. Microsoft использует их, тогда они перемещают типы в рамках .net. Это только значение, если вы не можете получить все ваши абоненты, чтобы перекомпилировать там код.

Ответ 5

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