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


433

У розділі "Властивості рішення" у мене встановлено "Випуск" для мого єдиного проекту.

На початку основної програми у мене є цей код, і він показує "Mode = Debug". У мене також є два рядки на самому верху:

#define DEBUG 
#define RELEASE

Я тестую правильну змінну?

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

Моя мета - встановити різні параметри за замовчуванням для змінних на основі режиму налагодження проти випуску.


13
Ви визначаєте BOTH налагодження та випуск.
Ерік Дальванґ

Відповіді:


719

DEBUG/ _DEBUGмає бути визначено в VS.

Видаліть #define DEBUGсвій код. Встановіть препроцесори в конфігурації збірки для цієї конкретної збірки.

Причина, в якій він друкує "Режим = Налагодження", пов'язана з вашим, #defineа потім пропускає elif.

Правильний спосіб перевірки:

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

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


77
Я хотів би додати, що якщо хтось хотів перевірити ПІДВИЩЕННЯ, то це можна зробити: #if! DEBUG

3
Чому #ifі ні #ifdef?
Боб Штейн

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

27
@Jess, я вважаю, що це Visual Studio займається
сірим кольором

1
@DakotahHicock Це правильно, я не використовую resharper, і VS сірий.
makoshichi

294

За замовчуванням Visual Studio визначає DEBUG, якщо проект складено в режимі налагодження, і не визначає його, якщо він знаходиться в режимі випуску. 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
Дивовижна відповідь, оцінено.
Дуй Тран

210

Я вважаю за краще перевіряти це так, як шукати #defineдирективи:

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

З застереженням, що, звичайно, ви могли скласти і розгортати щось у режимі налагодження, але все одно не налагоджувати налагоджувач.


1
Дякую! Я навіть не знаю, що таке "#defines", тому це чудове рішення!
Тім

І в моєму випадку це робить саме те, що я хочу. Я насправді хочу знати, чи є у мене доданий налагоджувач, тому що я знаю, що у мене є якийсь код, який я не хочу виконувати, якщо у мене доданий налагоджувач. Це круто!
JFTxJ

1
Якщо особисто вам подобається використовувати #IF DEBUGв ситуації налагодження код, який не повинен тривати. Для виробничого коду я згоден з використанням вищезазначеного.
Купи

10
Зворотний шлях до цього замість використання #DEBUGполягає в тому, що це, якщо оператор є у вашому коді і завжди перевіряється, де #DEBUGвідповідь видаляє код, який не застосовується під час компіляції, щоб у вас не було перевірки виконання та вашого. EXE (або все, що ви компілюєте) менше.
День

1
@ user34660. Відповідь на поставлене запитання - «ні», що насправді нікому не допомагає.
Стів Сміт

51

Я не є величезним шанувальником матеріалів #if, особливо якщо ви поширите його по всій своїй кодовій базі, оскільки це створить проблеми, коли налагодження налагодження проходить, але випуск версій провалюється, якщо ви не обережні.

Ось ось що я придумав (надихнув #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
Гей, це досить креативно. Мені подобається, що ти використовуєш атрибут для встановлення властивості.
kenchilada

3
Це має перевагу в тому, що не потрапляти через рефакторинг помилок в Resharper, які можуть зіпсувати ваш код на основі поточної умовної установки.
Джафін

3
Мені це подобається, але мені цікаво, чому б не створити для цього одиночну реалізацію замість служби. Це специфічна для системи система, і вона перешкоджає вам турбуватися про введення її всюди. (чи можете ви уявити сценарій, коли реалізація цієї функціональності була б різною?
BastanteCaro

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 . Якщо ви хочете визначити один з переходів до властивостей проекту, натисніть на вкладку Build і додайте 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 у властивостях Build Build


5

Простір імен

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 MANAGER) - цього недостатньо.

Вам потрібно звернути увагу на ПУБЛІКУ Configuration, як таку:

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


0

Оскільки мета цих директив COMPILER полягає в тому, щоб сказати компілятору НЕ включати код, налагоджувальний код, бета-код або, можливо, код, який потрібен усім кінцевим користувачам, за винятком тих, хто рекламний відділ, тобто #Define AdDept, який ви хочете вміти включати або видаляти їх залежно від ваших потреб. Без необхідності змінювати вихідний код, якщо, наприклад, не AdDept зливається в AdDept. Тоді все, що потрібно зробити, це включити директиву #AdDept на сторінку з властивостями компілятора існуючої версії програми та зробити компіляцію та wa la! код об'єднаної програми оживляє !.

Ви також можете використовувати декларацію для нового процесу, який не готовий до прайм-тайму або який не може бути активним у коді, поки не настав час його випустити.

Так чи інакше, це я роблю.


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.