Как установить переменную условной компиляции? - PullRequest
35 голосов
/ 01 октября 2010

В C / C ++ вы можете определять макросы в коде так:

#define OLD_WAY  1

Хотя я никогда не делал этого, я предполагаю, что то же самое доступно в C #. Более того, в C / C ++ можно затем сделать некоторую логику условной компиляции, выполнив что-то вроде этого:

#if OLD_WAY == 1
 int i = 0;
#else
 int i = 1;
#endif

ОК, это все круто и все такое. И снова я предполагаю, что такая логика возможна в C #. Что я хотел бы знать, так это как определить константы на уровне проекта, чтобы я мог использовать логику, которая позволит мне условно скомпилировать один блок кода, если я определю константу в одну сторону или другой блок кода если я не определю это так? Я предполагаю, что это сделано где-то в свойствах проекта, но как и где я могу это определить?

Ответы [ 3 ]

51 голосов
/ 16 апреля 2017

Компилятор C # csc.exe и сам язык C # не предоставляют никаких предопределенных констант для условной компиляции . Visual Studio добавляет только значения DEBUG и TRACE, которые можно настроить в среде IDE.В среде IDE также можно добавлять собственные произвольные символы, но, поскольку они являются по существу фиксированными (инвариантными) значениями, возможности ограничены.

Более мощные пользовательские параметры можно настроить, отредактировав проект .csproj вручную.файл.Вы можете установить условия здесь для выборочного распространения символов условной компиляции в C # на основе огромного количества информации о среде и конфигурации, доступной в MSBuild (см. здесь и здесь , но в принципе не может быть полного списка, поскольку разрозненные компоненты произвольно предоставляют метаданные ad-hoc ).

Давайте рассмотримрабочий пример.Один из случаев, когда полезно условно компилировать, - это если вы хотите написать код, который адаптируется к любым инструментам, обнаруженным во время сборки.Таким образом, вы можете использовать новейшие языковые функции, сохраняя при этом возможность компилирования на компьютерах с более старыми инструментами, которые, как и ожидалось, отклоняли бы чужой синтаксис и / или ключевые слова.Для конкретного случая C # 7.0 в Visual Studio 2017 мы можем изменить .csproj следующим образом:

.csproj файл (отрывок):

enter image description here

Вы также можете идентифицировать каждый из более старых компиляторов C #, постепенно снижая качество.То же самое касается обнаружения версии .NET Framework (часто запрашивается в StackOverflow [1] [2] [3] [4] ) и любые другие условия окружающей среды.Это оставлено в качестве упражнений для читателя, но в случае, если вы хотите скопировать / вставить выделенные строки сверху, вот текстовая версия.В качестве обновления снимка экрана я добавил здесь условные выражения в кавычки (хотя, казалось, что все работает без них)

<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>

В любом случае, теперь вы можете написать условный C #код с использованием #if… #elif… #else… #endif.Продолжая пример, в приведенном ниже коде используется новый синтаксис кортежа - доступный только в C # 7 - для замены элементов массива.Кстати, версия кортежа не только более лаконична и / или элегантна;он также производит отличный код IL:

#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, "неактивных" неактивных блоков кода и т. Д.

Iтакже упомянул, что MSBuild имеет сокровищницу доступной информации, из которых $(VisualStudioVersion) был только одним примером.К сожалению, нелегко узнать, какие значения доступны и какие они могут иметь во время сборки.Хитрость заключается в том, чтобы временно поместить проект C++ в ваше решение Visual Studio (если у вас его еще нет) вместе с проектом C #.Если вы щелкните правой кнопкой мыши свойства проекта для этого .vcxproj и затем посмотрите (например) «Дополнительные каталоги включения» на странице C/C++, в правом нижнем углу появится раскрывающееся меню, когда вы нажмете для редактирования.:

enter image description here

Вы получите диалоговое окно с кнопкой «Макросы», которую можно нажать, чтобы получить список всех доступных MSBuildпеременные плюс их ожидаемые значения в соответствии с платформой и конфигурацией, которые в данный момент выбраны в IDE.Не пропустите поля хорошо известные метаданные элемента (с префиксом %) внизу списка.

enter image description here

Вы можете получить представление о том, сколько вещей здесь, по размеру большого пальца полосы прокрутки на этом скриншоте.(Они перечислены в алфавитном порядке, я просто прокрутил эту часть раздела «P», потому что там было минимальное количество личной информации).Однако важно отметить, что как (доступные) переменные, так и их значения меняются с течением времени в ходе сборки, поэтому в этом списке вы можете найти элементы, которые недоступны для .csproj ввремя обработки .


[edit:] Еще один способ узнать, какие значения свойств доступны во время и во время процесса сборки, - установить для MSBuild «подробность вывода» значение «Подробно»и затем восстановить.

enter image description here

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

38 голосов
/ 01 октября 2010

В C # вы можете сделать #define, но вы не можете использовать значения для них, как в C ++.
Каждое определение может иметь 2 состояния: определено или не определено

В свойствах проекта в Build вы можете задать определения, которые должны быть определены.
Все, что вы укажете здесь, будет определено во всех ваших файлах проекта.

Так, например, я могу определить 2 условных символа компиляции в этом поле как:
MY_DEFINE1, MY_DEFINE2

Тогда в своем коде я могу делать такие вещи:

#if MY_DEFINE1
//do something conditionally
#endif

#if MY_DEFINE2
//do something else conditionally
#endif

В качестве альтернативы вы можете делать свои определения для каждого файла, но в отличие от C ++ они должны быть в верхней части вашего файла.

В верхней части вашего файла вы можете использовать:

#define MY_DEFINE2

или вы можете в начале вашего файла использовать:

#undef MY_DEFINE2

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

37 голосов
/ 01 октября 2010

Откройте свойства вашего проекта и посмотрите на страницу Build. Есть поле под названием Условные символы компиляции.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...