C # if / then директивы для отладки и выпуска


435

В свойствах решения у меня есть Конфигурация, установленная на «выпуск» для моего единственного проекта.

В начале основной процедуры у меня есть этот код, и он показывает «Mode = Debug». У меня также есть эти две строки в самом верху:

#define DEBUG 
#define RELEASE

Я проверяю правильную переменную?

#if (DEBUG)
            Console.WriteLine("Mode=Debug"); 
#elif (RELEASE)
            Console.WriteLine("Mode=Release"); 
#endif

Моя цель - установить разные значения по умолчанию для переменных в зависимости от режима отладки и выпуска.


13
Вы определяете ОБА отладки и выпуска.
Эрик Дальванг

Ответы:


720

DEBUG/ _DEBUGдолжны быть определены в VS уже.

Удалите #define DEBUGв своем коде. Установите препроцессоры в конфигурации сборки для этой конкретной сборки.

Причина, по которой он печатает «Mode = Debug», из-за вашего, #defineа затем пропускает elif.

Правильный способ проверить это:

#if DEBUG
    Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif

Не проверяйте RELEASE.


78
Я хотел бы добавить, что если кто-то только хотел проверить на RELEASE, то можно сделать это: #if! DEBUG

3
Почему #ifи нет #ifdef?
Боб Стейн

23
@ BobStein-VisiBone Помните, что мы говорим здесь о C #, а не C. #ifdefотносится к препроцессору C / C ++, C # требует использования #if.
jduncanator

27
@ Джесс, я полагаю, что это Visual Studio, а не ReSharper
Дакота Хикок

1
@DakotahHicock Правильно, я не использую Resharper, а VS скрывает это.
Макошичи

296

По умолчанию Visual Studio определяет DEBUG, если проект компилируется в режиме отладки, и не определяет его, если он находится в режиме выпуска. RELEASE не определяется в режиме Release по умолчанию. Используйте что-то вроде этого:

#if DEBUG
  // debug stuff goes here
#else
  // release stuff goes here
#endif

Если вы хотите сделать что-то только в режиме релиза:

#if !DEBUG
  // release...
#endif

Также стоит отметить, что вы можете использовать [Conditional("DEBUG")]атрибут в методах, которые возвращаются, voidчтобы они выполнялись, только если определен определенный символ. Компилятор удалит все вызовы этих методов, если символ не определен:

[Conditional("DEBUG")]
void PrintLog() {
    Console.WriteLine("Debug info");
}

void Test() {
    PrintLog();
}

6
Потрясающий ответ, приветствуется.
Duy Tran

211

Я предпочитаю проверять это так, а не искать #defineдирективы:

if (System.Diagnostics.Debugger.IsAttached)
{
   //...
}
else
{
   //...
}

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


1
Спасибо! Я еще даже не знаю, что такое "#defines", так что это отличное решение!
Тим

И в моем случае, это именно то, что я хочу. Я действительно хочу знать, есть ли у меня отладчик, потому что я знаю, что у меня есть код, который я не хочу выполнять, если у меня есть отладчик. Это круто!
JFTxJ

1
Если лично вам нравится использовать #IF DEBUGв ситуации отладки код, который не должен длиться долго. Для производственного кода я согласен с использованием выше.
Coops

10
Недостаток выполнения этого вместо использования #DEBUGсостоит в том, что оператор if находится в вашем коде и всегда проверяется, где в качестве #DEBUGответа удаляется код, который не применим во время компиляции, поэтому у вас нет проверки во время выполнения и вашей. exe (или все, что вы компилируете) меньше.
Дан

1
@ user34660. Ответ на поставленный вопрос - «нет», который никому не помогает.
Стив Смит

52

Я не большой поклонник вещей #if, особенно если вы распространяете их по всей базе кода, так как это создаст вам проблемы, когда сборки Debug проходят, но сборки Release терпят неудачу, если вы не будете осторожны.

Итак, вот что я придумал (вдохновленный #ifdef в C # ):

public interface IDebuggingService
{
    bool RunningInDebugMode();
}

public class DebuggingService : IDebuggingService
{
    private bool debugging;

    public bool RunningInDebugMode()
    {
        //#if DEBUG
        //return true;
        //#else
        //return false;
        //#endif
        WellAreWe();
        return debugging;
    }

    [Conditional("DEBUG")]
    private void WellAreWe()
    {
        debugging = true;
    }
}

2
Эй, это довольно креативно. Мне нравится ваше использование атрибута для установки свойства.
Кенчилада

3
Преимущество этого состоит в том, что в Resharper не возникает проблем с рефакторингом ошибок, которые могут испортить ваш код в зависимости от текущей условной установки.
Jafin

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

1
На самом деле у меня есть одноэлементная и сервисная реализация в одном классе, который я сейчас использую, так что у вас есть выбор, как его использовать ... Конечно, реализация сервиса имеет то преимущество, что ее легче "заглушить", поэтому что вы можете проверить оба пути кода ...
Тод Томсон

Мне интересно, почему DebuggingServiceне статический класс и зачем вам интерфейс? Это как-то связано с использованием этого с контейнером IoC?
Бен

23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

Метод Debug.Assertимеет условный атрибут DEBUG. Если он не определен, вызов и назначение isDebug = true будут устранены :

Если символ определен, вызов включен; в противном случае вызов (включая оценку параметров вызова) опускается.

Если DEBUGопределено, isDebugустанавливается в true(и передается Debug.Assert, что ничего не делает в этом случае).


Это тоже довольно креативное решение. :)
Джек,

Ницца. Для переменной итерации, которая должна меняться между отладкой и выпуском ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Мэтт Дэвис,

19

Если вы пытаетесь использовать переменную, определенную для типа сборки, вы должны удалить две строки ...

#define DEBUG  
#define RELEASE 

... это приведет к тому, что #if (DEBUG) всегда будет верным.

Также нет условного символа компиляции по умолчанию для RELEASE . Если вы хотите определить один переход к свойствам проекта, щелкните вкладку « Построение », а затем добавьте «RELEASE» в текстовое поле « Условные символы компиляции» под заголовком « Общие» .

Другим вариантом будет сделать это ...

#if DEBUG
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Release");
#endif

7

Удалить ваши определения в верхней части

#if DEBUG
        Console.WriteLine("Mode=Debug"); 
#else
        Console.WriteLine("Mode=Release"); 
#endif

7

Слегка измененная (убитая?) Версия ответа Тода Томсона как статическая функция, а не отдельный класс (я хотел иметь возможность вызывать ее в привязке представления WebForm из класса viewutils, который я уже включил).

public static bool isDebugging() {
    bool debugging = false;

    WellAreWe(ref debugging);

    return debugging;
}

[Conditional("DEBUG")]
private static void WellAreWe(ref bool debugging)
{
    debugging = true;
}

6

Обязательно определите константу DEBUG в свойствах сборки проекта. Это позволит #if DEBUG. Я не вижу заранее определенной константы RELEASE, поэтому это может означать, что все, что не находится в блоке DEBUG, находится в режиме RELEASE.

Определите постоянную DEBUG в свойствах сборки проекта


5

NameSpace

using System.Resources;
using System.Diagnostics;

метод

   private static bool IsDebug()
    {
        object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
        if ((customAttributes != null) && (customAttributes.Length == 1))
        {
            DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
            return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
        }
        return false;
    }

3

Совет, который может сэкономить вам много времени - не забывайте, что даже если вы выбираете debugв конфигурации сборки (в меню vs2012 / 13 она находится в разделе BUILD => КОНФИГУРАЦИОННЫЙ МЕНЕДЖЕР) - этого недостаточно.

Вам нужно обратить внимание на ИЗДАНИЕ Configuration, как таковое:

введите описание изображения здесь


0

Поскольку целью этих директив COMPILER является указание компилятору НЕ включать код, отладочный код, бета-код или, возможно, код, который нужен всем вашим конечным пользователям, за исключением, скажем, тех, кто занимается рекламным отделом, т.е. #Define AdDept, который вы хотите быть в состоянии включить или удалить их в зависимости от ваших потребностей. Без необходимости изменять исходный код, если, например, не AdDept сливается с AdDept. Тогда все, что нужно сделать, это включить директиву #AdDept на странице свойств параметров компилятора существующей версии программы и выполнить компиляцию, и все! код объединенной программы оживает !.

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

Во всяком случае, так я это делаю.


0

Я подумал о лучшем способе. До меня дошло, что блоки #if фактически являются комментариями в других конфигурациях (при условии DEBUGили RELEASE; но верно для любого символа)

public class Mytest
    {
        public DateTime DateAndTimeOfTransaction;
    }

    public void ProcessCommand(Mytest Command)
        {
            CheckMyCommandPreconditions(Command);
            // do more stuff with Command...
        }

        [Conditional("DEBUG")]
        private static void CheckMyCommandPreconditions(Mytest Command)
        {
            if (Command.DateAndTimeOfTransaction > DateTime.Now)
                throw new InvalidOperationException("DateTime expected to be in the past");
        }

0

Удалите определения и проверьте, находится ли условие в режиме отладки. Вам не нужно проверять, находится ли директива в режиме выпуска.

Что-то вроде этого:

#if DEBUG
     Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.