И объединять или отменять символы ConditionaAttribute, чтобы избежать генерации вызова MSIL
Мне нужно сделать некоторую условную компиляцию в C#, но мне также было предложено сохранить глобальное количество символов низким. Так что вместо #if ENABLE_MODULE
(И добавляя много символов), я в основном отключаюсь #if !DISABLE_MODULE
,
При профилировании циклов ядра я хочу иметь точный контроль над тем, что отключается, чтобы более четко взглянуть на результаты. Но даже для пустых вызовов assert (#if
внутри тела метода), только вызовы суммируют значительное время. Вот почему я начал использовать [Conditional]
атрибут, чтобы удалить вызов вообще и избежать необходимости заключать все в #if
разделы, которые делают код менее читабельным.
Но [Conditional]
имеет некоторые предостережения:
- Может быть только ИЛИ-ed вместе.
- Отрицание с помощью нет! внутри условно не допускается.
- Нет способа объединить их.
- В отличие от #if, он интерпретируется определениями символов области файла вызывающего абонента вместо фактических определений символов области файла вызываемого метода.
Я нашел обходной путь, но это не красиво и имеет тенденцию повторять код (см. __Convoluted()
методы ниже). Код внутри отключен #if
разделы обрабатываются как комментарии в Visual Studio (так что рефакторы имен отсутствуют), что ухудшает ситуацию, превращается в неработающие коммиты из-за не проверки всех комбинаций символов и т. д.
Я думал об использовании некоторых зонтичных символов, но это заставляет меня думать обо всем положительно-ИЛИ, и иногда я хочу, например, большинство утверждений, но не утверждение из какого-то модуля.
Возможно, это скорее ответ на программную архитектуру, чем на практический.
Я использую Unity, и поэтому не могу точно контролировать символы для каждой конфигурации (отладка / выпуск / сборка разработки) без выполнения сценариев сборки, которые заменяют параметры компилятора внутри файла (csc.rsp)
Мой вопрос: есть ли лучший способ справиться с этим?
Спасибо за ваше время.
Я сделал небольшую домашнюю работу, пробуя разные альтернативы, и пришел к некоторым выводам (следующий код)
Минимальный контрольный пример консольного приложения C# .NET
Служебный файл
//ENABLE is a global symbol definition at project level
#if ENABLE && EXTRA
#define _COMBINED
#endif
#if !ENABLE
#define _DISABLE
#endif
using System;
using System.Diagnostics;
public static class Utility {
[Conditional("ENABLE")]
public static void Call(string msg) {
Console.WriteLine(msg);
}
[Conditional("ENABLE"), Conditional("OTHER")]
public static void CallOr(string msg) {
Console.WriteLine(msg);
}
[Conditional("_DISABLE")]
public static void CallNot(string msg) {
Console.WriteLine(msg);
}
public static void CallNotInternal(string msg) {
CallNot(msg);
}
[Conditional("_COMBINED")]
public static void CallAnd(string msg) {
Console.WriteLine(msg);
}
public static void CallAndInternal(string msg) {
CallAnd(msg);
}
#if ENABLE //!_DISABLE
[Conditional("_NEVER")] // <-- Hack to remove MSIL call.
public static void CallNotConvoluted(string msg) { }
#else
public static void CallNotConvoluted(string msg) {
Console.WriteLine(msg);
}
#endif
#if !(ENABLE && EXTRA) //!_COMBINED
[Conditional("_NEVER")] // <-- Hack to remove MSIL call.
public static void CallAndConvoluted(string msg) { }
#else
public static void CallAndConvoluted(string msg) {
Console.WriteLine(msg);
}
#endif
}
Различные комбинации вызовов
//Works as expected
Utility.Call("Call1");
//Works as expected
Utility.CallOr("CallOr");
//Doesn't work because _DISABLE is not defined in this file
//(although it is defined at Utility)
Utility.CallNot("CallNot");
//Works because _DISABLE is defined at Utility (where CallNotInternal resides)
//BUT would have extra "empty" call
Utility.CallNotInternal("CallNotInternal");
//Doesn't work because _COMBINED is not defined in this file
//(although it is defined at Utility)
Utility.CallAnd("CallAnd");
//Works because _COMBINED is defined at Utility (where CallAndInternal resides)
//BUT would have extra "empty" call
Utility.CallAndInternal("CallAndInternal");
//Works but it seems kind of hacky/bulky
Utility.CallNotConvoluted("CallNotConvoluted");
//Works but it seems kind of hacky/bulky
Utility.CallAndConvoluted("CallAndConvoluted");
Код выводится, когда глобальные символы устанавливают следующее. Заметить, что CallAnd
а также CallNot
покажите, что Conditional не работает как #if.
ENABLE and EXTRA
----------------
Call1
CallOr
CallAndInternal
CallAndConvoluted
ENABLE
-----
Call1
CallOr
(no symbols)
------------
CallNotInternal
CallNotConvoluted