Генераторы кода работают внутри компилятора. Они запускаются при каждой сборке и при каждом нажатии клавиши в IDE. Если не следить за ними, билд на 10 секунд может превратиться в полторы минуты без видимых причин. Вот что можно сделать, чтобы этого не допустить.
Сделайте сгенерированный код видимым
По умолчанию сгенерированные
.g.cs файлы не записываются на диск. Они существуют только в памяти компилятора. Когда что-то ломается, вы видите ошибку в файле, который не можете открыть.Добавьте в
Directory.Build.props в корне решения:<Project>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>
$(BaseIntermediateOutputPath)generated
</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>
Теперь все сгенерированные файлы попадают в папку
obj/generated. Их можно читать, искать по ним и ставить точки останова в отладчике. Это настройка на один раз, и она стоит того.Замеряйте время через binary log
Ощущение «билд стал медленнее» ничего не даёт. Нужны конкретные числа по каждому генератору. Соберите проект с флагом:
dotnet build -bl
Откройте полученный
msbuild.binlog в MSBuild Structured Log Viewer. Найдите задачу CSC. Внутри будет список всех генераторов с временем выполнения в миллисекундах. Собирайте именно полное решение, а не отдельный проект. Стоимость генератора умножается на количество проектов, которые его подтягивают.Проверьте транзитивные зависимости
Генераторы кода приезжают вместе с NuGet-пакетами. Вы подключаете библиотеку логирования или маппер, а внутри пакета лежит генератор, который теперь запускается в каждом проекте. Вы его не выбирали, но он работает.
В том же binary log задача CSC показывает все загруженные сборки анализаторов и генераторов. Пройдитесь по списку. Если видите незнакомое имя, выясните, откуда оно пришло. Команда
dotnet nuget why поможет отследить цепочку зависимостей.Используйте только инкрементальные генераторы
Если вы пишете свои генераторы, реализуйте
IIncrementalGenerator, а не устаревший ISourceGenerator. Инкрементальный генератор кеширует промежуточные результаты. Если входные данные не изменились, он пропускает повторную обработку.Но сам по себе интерфейс ничего не гарантирует. Генератор, который реализует
IIncrementalGenerator и при этом пересобирает всё заново на каждый вызов, работает так же медленно, как устаревший. Кеширование должно быть реальным. Пайплайн нужно строить так, чтобы неизменённые входы давали кешированный выход.Принимайте решения по числам
Если дорогой генератор пришёл из стороннего пакета, вы не можете его исправить. Но можете решить, стоит ли пакет своего времени сборки. Иногда стоит. Иногда дешевле отказаться от пакета и решить задачу иначе.
Главное тут не гадать, а смотреть в binary log. Там есть имя генератора и его стоимость в миллисекундах. Этого достаточно, чтобы принять осознанное решение.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view