C # if / then direttive per debug vs release


434

Nelle proprietà della soluzione, la configurazione è impostata su "release" per il mio unico progetto.

All'inizio della routine principale, ho questo codice e mostra "Mode = Debug". Ho anche queste due righe in cima:

#define DEBUG 
#define RELEASE

Sto testando la variabile giusta?

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

Il mio obiettivo è impostare valori predefiniti diversi per le variabili in base alla modalità debug vs release.


13
Stai definendo ENTRAMBE debug e rilascio.
Eric Dahlvang,

Risposte:


720

DEBUG/ _DEBUGdovrebbe essere già definito in VS.

Rimuovi il #define DEBUGnel tuo codice. Imposta i preprocessori nella configurazione build per quella build specifica.

Il motivo per cui stampa "Mode = Debug" è a causa tua #definee quindi salta il file elif.

Il modo giusto per verificare è:

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

Non controllare RELEASE.


78
Volevo aggiungere che se si volesse verificare solo STAMPA, si può fare questo: #if! DEBUG

3
Perché #ife no #ifdef?
Bob Stein,

23
@ BobStein-VisiBone Ricorda che stiamo parlando di C # qui, non C. #ifdefè specifico per il preprocessore di C / C ++, C # impone l'uso di #if.
congiuntore

27
@Jess, credo che questo sia Visual Studio che fa ingrigire, non ReSharper
Dakotah

1
@DakotahHicock Esatto, non uso il resharper e VS lo disabilita.
Makoshichi,

295

Per impostazione predefinita, Visual Studio definisce DEBUG se il progetto è compilato in modalità Debug e non lo definisce se è in modalità Release. RELEASE non è definito in modalità Rilascio per impostazione predefinita. Usa qualcosa del genere:

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

Se vuoi fare qualcosa solo in modalità di rilascio:

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

Inoltre, vale la pena sottolineare che è possibile utilizzare l' [Conditional("DEBUG")]attributo sui metodi che ritornano voidper averli eseguiti solo se viene definito un determinato simbolo. Il compilatore rimuove tutte le chiamate a tali metodi se il simbolo non è definito:

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

void Test() {
    PrintLog();
}

6
Risposta fantastica, apprezzata.
Duy Tran,

211

Preferisco controllarlo in questo modo piuttosto che cercare #definedirettive:

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

Con l'avvertenza che, ovviamente, è possibile compilare e distribuire qualcosa in modalità debug ma non è ancora collegato il debugger.


1
Grazie! Non so ancora cosa siano le "#define", quindi questa è un'ottima soluzione!
Tim

E nel mio caso, fa esattamente quello che voglio. In realtà voglio sapere se ho un debugger collegato, perché so di avere un codice che non voglio eseguito se ho un debugger collegato. Questo è bellissimo!
JFTxJ,

1
Se personalmente piace usare #IF DEBUGin una situazione di codice di debug che non dovrebbe durare. Per il codice di produzione sono d'accordo con l'utilizzo di quanto sopra.
Coop il

10
L'inconveniente di fare questo invece di usare #DEBUGè che questa istruzione if è nel tuo codice e viene sempre controllata dove la #DEBUGrisposta rimuove il codice che non è applicabile al momento della compilazione, quindi non hai un controllo di runtime e il tuo. exe (o qualunque cosa tu compili) è più piccolo.
Dan

1
@ user34660. La risposta alla domanda dichiarata è "no", il che non aiuta davvero nessuno.
Steve Smith,

52

Non sono un grande fan delle cose #if, specialmente se lo diffondi in tutto il tuo codice perché ti darà problemi dove passano le build di Debug ma le build di Release falliscono se non stai attento.

Quindi, ecco cosa mi è venuto in mente (ispirato a #ifdef in 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
Ehi ora, è abbastanza creativo. Mi piace il tuo uso dell'attributo per impostare la proprietà.
Kenchilada,

3
Questo ha il vantaggio di non essere colpito dal refactoring di bug in Resharper che può rovinare il tuo codice in base all'attuale configurazione condizionale.
Jafin,

3
Mi piace questo, ma mi chiedo perché non creare un'implementazione singleton per questo invece di un servizio. È specifico del sistema e ti impedisce di doverti iniettare ovunque. (puoi immaginare uno scenario in cui l'implementazione di questa funzionalità sarebbe diversa?
BastanteCaro

1
In realtà ho un'implementazione singleton e di servizio in una classe che sto usando ora in modo da poter scegliere il modo in cui usarlo ... Naturalmente l'implementazione del servizio ha il vantaggio di essere più facile da "stub" fuori così che puoi testare entrambi i percorsi del codice ...
Tod Thomson,

Mi chiedo perché DebuggingServicenon sia una classe statica e perché hai bisogno di un'interfaccia? È qualcosa a che fare con l'utilizzo di questo con un contenitore IoC?
Ben

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

Il metodo Debug.Assertha attributo condizionale DEBUG. Se non è definito, la chiamata e l'assegnazione isDebug = true vengono eliminati :

Se il simbolo è definito, la chiamata è inclusa; in caso contrario, la chiamata (inclusa la valutazione dei parametri della chiamata) viene omessa.

Se DEBUGè definito, isDebugè impostato su true(e passato a Debug.Assert, che in questo caso non fa nulla).


Questa è anche una soluzione abbastanza creativa. :)
Jack,

Bello. Per una variabile di iterazione che deve cambiare tra Debug e Release ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis,

19

Se stai cercando di utilizzare la variabile definita per il tipo di build, dovresti rimuovere le due righe ...

#define DEBUG  
#define RELEASE 

... questo farà sì che #if (DEBUG) sia sempre vero.

Inoltre non esiste un simbolo di compilazione condizionale predefinito per RELEASE . Se si desidera definirne uno, accedere alle proprietà del progetto, fare clic sulla scheda Genera, quindi aggiungere RILASCIO alla casella di testo Simboli di compilazione condizionale sotto l' intestazione Generale .

L'altra opzione sarebbe quella di fare questo ...

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

7

Rimuovi le tue definizioni in alto

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

7

Versione leggermente modificata (bastardata?) Della risposta di Tod Thomson come una funzione statica piuttosto che una classe separata (volevo essere in grado di chiamarla in una vista WebForm da una classe viewutils che avevo già incluso).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

6

Assicurati di definire la costante DEBUG nelle proprietà di costruzione del progetto. Ciò consentirà il #if DEBUG. Non vedo una costante RELEASE predefinita, quindi ciò potrebbe implicare che qualsiasi cosa non presente in un blocco DEBUG sia in modalità RELEASE.

Definire la costante DEBUG in Proprietà build progetto


5

NameSpace

using System.Resources;
using System.Diagnostics;

Metodo

   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

Un consiglio che può farti risparmiare un sacco di tempo - non dimenticare che anche se scegli debugsotto la configurazione della build (nel menu vs2012 / 13 è sotto BUILD => CONFIGURATION MANAGER) - non è abbastanza.

Devi prestare attenzione al PUBBLICO Configuration, in quanto tale:

inserisci qui la descrizione dell'immagine


0

Poiché lo scopo di queste direttive del compilatore è di dire al compilatore di NON includere il codice, il codice di debug, il codice beta o forse il codice necessario a tutti gli utenti finali, ad eccezione di quelli del dipartimento pubblicitario, ad esempio #Define AdDept che si desidera essere in grado di includerli o rimuoverli in base alle proprie esigenze. Senza dover modificare il codice sorgente se, ad esempio, un AdDept si fonde nell'AdDept. Quindi tutto ciò che deve essere fatto è includere la direttiva #AdDept nella pagina delle proprietà delle opzioni del compilatore di una versione esistente del programma ed eseguire una compilazione e attendere! il codice del programma unito prende vita !.

Potresti anche voler utilizzare un dichiarativo per un nuovo processo che non è pronto per la prima serata o che non può essere attivo nel codice fino a quando non è il momento di rilasciarlo.

Ad ogni modo, è così che lo faccio.


0

Devo pensare a un modo migliore. Mi sono reso conto che i blocchi #if sono effettivamente commenti in altre configurazioni (assumendo DEBUGo RELEASE; ma vero con qualsiasi simbolo)

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

Rimuovere le definizioni e verificare se il condizionale è in modalità debug. Non è necessario verificare se la direttiva è in modalità di rilascio.

Qualcosa come questo:

#if DEBUG
     Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.