Ответ 1
Компилятор С# csc.exe
и сам язык С# не предоставляют никаких предопределенных констант для условной компиляции. Visual Studio добавляет только значения DEBUG
и TRACE
, которые можно настроить через IDE. Среда IDE также позволяет добавлять собственные произвольные символы, но, поскольку они являются по существу фиксированными (инвариантными) значениями, возможности ограничены.
Более мощные пользовательские параметры можно настроить, отредактировав файл проекта .csproj
вручную. Вы можете настроить условия здесь, чтобы выборочно распространять символы условной компиляции в С# на основе огромного количества информации о среде и конфигурации, доступной в MSBuild (см. здесь и здесь, но в принципе не может быть полного списка, поскольку разрозненные компоненты произвольно предоставляют метаданные ad-hoc).
Давайте рассмотрим рабочий пример. Один из случаев, когда полезно условно компилировать, - это если вы хотите написать код, который адаптируется к любым инструментам, обнаруженным во время сборки. Таким образом, вы можете использовать новейшие языковые функции, сохраняя при этом возможность компилирования на компьютерах с более старыми инструментами, которые, как и ожидалось, отклоняли бы чужой синтаксис и/или ключевые слова. Для конкретного случая С# 7.0 в Visual Studio 2017 мы можем изменить .csproj
следующим образом:
Файл .csproj (выдержка):
Вы также можете идентифицировать каждый из старых компиляторов С#, постепенно снижая качество. То же самое касается обнаружения версии .a Framework (часто запрашивается в Qaru [1] [2] [3] [4]) и любые другие условия окружающей среды. Это оставлено в качестве упражнений для читателя, но в случае, если вы хотите скопировать/вставить выделенные строки сверху, вот текстовая версия. В качестве обновления снимка экрана я добавил здесь условные выражения в кавычки (хотя казалось, что все работает без них)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
В любом случае, теперь вы можете написать условный код С#, используя #if… #elif… #else… #endif
. Продолжая пример, в приведенном ниже коде используется новый синтаксис кортежа - доступный только в С# 7 - для замены элементов массива. Кстати, версия кортежа не только более лаконична и/или элегантна; он также производит отличный код CIL:
#if CSHARP7
(rg[i], rg[j]) = (rg[j], rg[i]); // Swap elements: tuple syntax
#else
var t = rg[i]; // Swap elements: clunky
rg[i] = rg[j];
rg[j] = t;
#endif
Обратите внимание, что Visual Studio IDE правильно обрабатывает ваши ручные настройки .csproj
во всех отношениях. Учитывая .csproj
, который я показал ранее, редактор кода IDE правильно распознает и оценивает условную компиляцию для целей IntelliSense
, refactoring
, "неактивных" неактивных блоков кода и т.д.
Я также упомянул, что MSBuild обладает огромным запасом информации, из которых $(VisualStudioVersion)
был только одним примером. К сожалению, нелегко узнать, какие значения доступны и какие они могут иметь во время сборки. Хитрость заключается в том, чтобы временно поместить проект C++ в решение Visual Studio (если у вас его еще нет) вместе с проектом С#. Если вы щелкните правой кнопкой мыши свойства проекта для этого .vcxproj
, а затем посмотрите (например) "Дополнительные каталоги включения" на странице C/C++
, в правом нижнем углу появится раскрывающийся список, когда вы щелкните, чтобы редактировать :
Вы получите диалоговое окно с кнопкой "Макросы", которую вы можете щелкнуть, чтобы получить список всех доступных переменных MSBuild плюс их ожидаемые значения в соответствии с платформой и конфигурацией, которые в настоящее время выбраны в IDE. Не пропустите хорошо известные поля метаданных элемента (с префиксом %
) внизу списка.
Вы можете получить представление о том, сколько вещей здесь, по размеру большого пальца полосы прокрутки на этом скриншоте. (Они перечислены в алфавитном порядке; я просто прокрутил эту часть раздела "P", потому что там было минимальное количество личной информации.) Однако важно отметить, что как (доступные) переменные, так и их значения изменяются с течением времени в течение ход сборки, поэтому вы можете найти в этом списке элементы, которые не были доступны вашему .csproj
во время его обработки.
Другой способ узнать, какие значения свойств доступны во время и во время процесса сборки, - установить для MSBuild "подробность вывода" значение "Подробно", а затем перестроить.
После завершения сборки проверьте верхнюю часть журнала сборки в Visual Studio Окно вывода, и вы увидите список доступных имен свойств вместе с их начальными значениями.