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

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

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

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

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

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

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

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

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

person Dan Tao    schedule 03.07.2010    source источник
comment
Это происходит со мной все время ... мой проект Egg выдает «Chicken.dll не найден ...», в то время как мой проект Chicken выдает аналогичную ошибку. Хо-хм.   -  person Charlie Salts    schedule 03.07.2010
comment
Платформа .NET внутри использует взаимозависимые сборки. Кто-то узнал об этом некоторое время назад после разборки сборок .NET и задал этот вопрос на SO (хотя ссылку не могу найти).   -  person Alex    schedule 03.07.2010
comment
@ Алекс, да, я нашел это однажды. Мне показалось, что он сделал это через отражение.   -  person Joshua    schedule 03.07.2010
comment
@Charlie Salts: Вы смеетесь над вопросом? Я понимаю, что вы говорите, но я думал, что рассмотрел этот аргумент в том, что я написал.   -  person Dan Tao    schedule 03.07.2010
comment
Просто внес немного легкомыслия в интересный вопрос;) Я с нетерпением жду отличных ответов. +1   -  person Charlie Salts    schedule 03.07.2010


Ответы (5)


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

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

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

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

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

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

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

ПРИМЕЧАНИЕ:

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

ДАЛЬШЕ:

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

person Joshua    schedule 03.07.2010
comment
Вы можете иметь циклы в типах сигнатур методов, используя еще более сложный процесс сборки: сначала определите все классы и скомпилируйте их, затем настройте иерархию наследования (используя заглушки из предыдущего шага) и добавьте все методы без переопределения ( но без тел), и на третьем проходе, наконец, выполнить обычную компиляцию (теперь, наконец, включая тела методов). Если вы действительно хотите это сделать, #if станет вашим новым лучшим другом. - person Daniel; 03.07.2010

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

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

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

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

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

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

person Patrick from NDepend team    schedule 29.08.2010
comment
Очень продуманный и информативный ответ. Однако я просто хочу отметить, что я в основном задавал этот вопрос с точки зрения желания иметь возможность написать компонент в сочетании C# и VB.NET. Итак, хотя я понимаю, что вы имеете в виду под суперкомпонентом, я чувствую, что это не совсем соответствует тому, что я искал. Для меня суперкомпонент — это комбинация нескольких взаимозависимых компонентов; с другой стороны, смешанный компонент, как я его назову, будет декомпозицией (по языку) одного компонента на взаимозависимые части. Имеет ли это смысл? - person Dan Tao; 29.08.2010
comment
Вы должны выбрать VB.NET или C# и перенести другой язык на выбранный язык (например, с помощью .NET Reflector, который может преобразовывать код C# в код VB.NET или наоборот). Не может быть веских причин для поддержки двух языков для кодирования одной и той же сборки. - person Patrick from NDepend team; 30.08.2010

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

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

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

person zebediah49    schedule 03.07.2010
comment
К вашему сведению, в родных C и C++ мы достигаем этого благодаря файлам заголовков. - person Joshua; 03.07.2010
comment
@ Джошуа, это работает, если обе взаимозависимые вещи скомпилированы и связаны одновременно. Описание ответа «отключение функций, которых еще не существует» часто используется для прерывания циклов на уровне пакета с помощью менеджера пакетов. - person binki; 07.07.2014

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

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


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

person Ian Ringrose    schedule 19.10.2010

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

person TTT    schedule 03.12.2015