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

Это, наверное, звучит как глупый вопрос, но я все равно попробую.

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

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

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

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

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

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

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

5 ответов

Решение

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

Тебе понадобится:

  1. Сборка А
  2. Сборка Б
  3. Заглушка в сборе B

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

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

  1. Скомпилируйте сборку заглушки B
  2. Скопируйте заглушку сборки B в выходной каталог сборки B
  3. Сборка сборки А
  4. Сборка сборки B

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

НОТА:

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

В ДАЛЬНЕЙШЕМ:

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

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

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

альтернативный текст

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

Циклы зависимости между компонентами приводят к тому, что обычно называют спагетти-кодом или запутанным кодом. Если компонент A зависит от B, который зависит от C, который зависит от A, компонент A не может быть разработан и протестирован независимо от B и C. A, B и C образуют неделимую единицу, своего рода суперкомпонент. Этот суперкомпонент имеет более высокую стоимость, чем сумма затрат по сравнению с A, B и C, из-за явления экономии масштаба (хорошо задокументировано в статье "Оценка программного обеспечения: демистификация черного искусства" Стива Макконнелла). По сути, это говорит о том, что стоимость разработки неделимого фрагмента кода увеличивается в геометрической прогрессии.

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

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

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

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

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

Тем не менее, я не ожидаю, что визуальная студия когда-либо обойдёт это.


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

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

Другие вопросы по тегам