Когда создавать и распространять "справочные сборки"?

C# 7.1 ввел несколько новых параметров командной строки, чтобы помочь создать "эталонные сборки". По документации он выводит сборку, которая:

замените тела их методов единичным нулевым телом, но включите все члены, кроме анонимных типов.

Я нашел интересное замечание, что оно более стабильно при изменениях:

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

и что это наверное нужно для самого рослина..

Мы будем вводить вторую концепцию, которая называется "опорные сборки" (также называемые каркасными сборками). [---] Они будут использоваться для сценариев сборки.

.. какими бы ни были эти "сценарии сборки" для Roslyn.

Я понимаю, что для обычных пользователей сборки.NET такая сборка, вероятно, меньше и немного быстрее загружается для отражения. Да, но:

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

Это полезность кажется довольно нишевым.

Итак, я задаюсь вопросом о стороне производителя общих сборок - когда следует явно использовать эти новые флаги компилятора для создания эталонной сборки? Есть ли у него какое-либо практическое применение вне самого Roslyn?

1 ответ

Решение

Мотивация для этой функции - это действительно сценарии сборки, но они не специфичны для Roslyn; это тоже ваши сценарии сборки.

Когда вы собираете свой проект, движок сборки (MSBuild) должен решить, является ли каждый выход сборки актуальным по отношению к его входам. Например, если вы ничего не меняете и просто запускаете сборку дважды подряд, во второй раз не нужно вызывать компилятор C#: сборка уже была правильной.

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

Предположим, у вас есть решение, содержащее B.exe это зависит от A.dll,

Командная строка компилятора для B будет выглядеть примерно так

csc.exe /out:B.exe /r:..\A\bin\A.dll Program.cs

И его вклад будет

  • Источник для Б (Program.cs)
  • Сборка для А.

Если вы измените источник A и создадите свое решение, компилятор должен работать для A, создавая новый A.dll, Тогда, так как A.dll является входом для компиляции B, B также должен быть перекомпилирован.

Использование эталонной сборки для A немного меняет это

csc.exe /out:B.exe /r:..\A\bin\ref\A.dll Program.cs

Ввод для A теперь является его эталонной сборкой, а не реализацией / нормальной сборкой.

Поскольку эталонная сборка меньше полной сборки, это само по себе незначительно влияет на время сборки. Но этого недостаточно, чтобы оправдать эту особенность. Важно то, что компилятор заботится только о публичной поверхности API переданных ссылок. Если внутренняя деталь реализации сборки изменилась, сборки, на которые она ссылается, не нужно перекомпилировать для получения нового поведения. Как упоминает @Hans Passant в комментариях, именно так.NET Framework может обеспечить совместимые улучшения производительности и исправления ошибок в неизмененном пользовательском коде.

Преимущество функции эталонных сборок связано с работой MSBuild по их использованию. Предположим, вы изменили внутреннюю деталь реализации в A, но не изменили ее открытый интерфейс. На следующей сборке

  • Компилятор должен работать для A, потому что исходные файлы для A изменены.
  • Компилятор испускает оба A.dll (с измененной реализацией) и ref\A.dll, что идентично предыдущей справочной сборке.
  • поскольку ref\A.dll идентичен предыдущему выводу, он не копируется в выходную папку А.
  • Когда приходит время запустить компилятор B, он видит, что ни один из его входных данных не изменился - ни собственный код B, ни ссылочная сборка A, поэтому компилятору не нужно запускаться.
  • B затем копирует обновленный A.dll на его выходе и готов к работе с новым поведением.

Эффект пропуска последующей компиляции может усугубляться, когда вы переходите к большому решению - изменение комментария в {ProjectName}.Utilities.dll больше не требует все строить!

Многие изменения включают в себя изменение как публичной поверхности API, так и внутренней реализации, поэтому это изменение не ускоряет все сборки, но ускоряет многие сборки.

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