C # if / then-Anweisungen für Debug vs Release

432

In den Lösungseigenschaften ist die Konfiguration für mein einziges Projekt auf "Freigeben" festgelegt.

Zu Beginn der Hauptroutine habe ich diesen Code und er zeigt "Mode = Debug". Ich habe auch diese beiden Zeilen ganz oben:

#define DEBUG 
#define RELEASE

Teste ich die richtige Variable?

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

Mein Ziel ist es, verschiedene Standardeinstellungen für Variablen festzulegen, die auf dem Debug- und dem Release-Modus basieren.

NealWalters
quelle
13
Sie definieren BEIDES Debuggen und Freigeben.
Eric Dahlvang

Antworten:

718

DEBUG/ _DEBUGsollte bereits in VS definiert sein.

Entfernen Sie das #define DEBUGin Ihrem Code. Legen Sie Präprozessoren in der Build-Konfiguration für diesen bestimmten Build fest.

Der Grund, warum "Mode = Debug" gedruckt wird, liegt an Ihrem #defineund überspringt dann das elif.

Der richtige Weg zu überprüfen ist:

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

Nicht nachsehen RELEASE.

Psychotik
quelle
77
Ich wollte hinzufügen, dass, wenn man nur nach RELEASE suchen wollte, man dies tun kann: #if! DEBUG
3
Warum #ifund nicht #ifdef?
Bob Stein
23
@ BobStein-VisiBone Denken Sie daran, dass es sich hier um C # handelt, nicht um C. #ifdef, das für den Präprozessor von C / C ++ spezifisch ist. C # schreibt die Verwendung von vor #if.
jduncanator
27
@ Jess, ich glaube, dies ist Visual Studio, das das Ausgrauen macht, nicht ReSharper
Dakotah Hicock
1
@ DakotahHicock Das stimmt, ich benutze keinen Resharper und VS färbt es aus.
Makoshichi
294

Standardmäßig definiert Visual Studio DEBUG, wenn das Projekt im Debug-Modus kompiliert wird, und definiert es nicht, wenn es sich im Release-Modus befindet. RELEASE ist standardmäßig nicht im Release-Modus definiert. Verwenden Sie so etwas:

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

Wenn Sie etwas nur im Release-Modus tun möchten:

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

Es ist auch erwähnenswert, dass Sie [Conditional("DEBUG")]Attribute für Methoden verwenden können, die zurückkehren void, um sie nur auszuführen, wenn ein bestimmtes Symbol definiert ist. Der Compiler würde alle Aufrufe dieser Methoden entfernen, wenn das Symbol nicht definiert ist:

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

void Test() {
    PrintLog();
}
Mehrdad Afshari
quelle
6
Super Antwort, geschätzt.
Duy Tran
210

Ich ziehe es vor, es so zu überprüfen, anstatt nach #defineAnweisungen zu suchen :

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

Mit der Einschränkung, dass Sie natürlich etwas im Debug-Modus kompilieren und bereitstellen können, aber den Debugger immer noch nicht angehängt haben.

Joel Coehoorn
quelle
1
Vielen Dank! Ich weiß noch nicht einmal, was "#defines" sind, also ist dies eine großartige Lösung!
Tim
Und ich bin mein Fall, das macht genau das, was ich will. Ich möchte eigentlich wissen, ob ich einen Debugger angehängt habe, weil ich weiß, dass ich Code habe, den ich nicht ausführen möchte, wenn ich einen Debugger angehängt habe. Das ist fantastisch!
JFTxJ
1
Wenn Sie persönlich gerne #IF DEBUGDebugging-Code verwenden, sollte dies nicht von Dauer sein. Für den Produktionscode stimme ich der Verwendung des oben genannten zu.
Coops
10
Der Nachteil dabei #DEBUGist, dass diese if-Anweisung in Ihrem Code enthalten ist und immer überprüft wird, wo als #DEBUGAntwort der Code entfernt wird, der zur Kompilierungszeit nicht anwendbar ist, sodass Sie keine Laufzeitprüfung haben und Ihre. exe (oder was auch immer Sie kompilieren) ist kleiner.
Dan
1
@ user34660. Die Antwort auf die gestellte Frage lautet "Nein", was niemandem wirklich hilft.
Steve Smith
51

Ich bin kein großer Fan des # if-Materials, besonders wenn Sie es über Ihre gesamte Codebasis verteilen, da es Ihnen Probleme gibt, wenn Debug-Builds erfolgreich sind, Release-Builds jedoch fehlschlagen, wenn Sie nicht vorsichtig sind.

Folgendes habe ich mir ausgedacht (inspiriert von #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;
    }
}
Tod Thomson
quelle
2
Hey, das ist ziemlich kreativ. Ich mag Ihre Verwendung des Attributs zum Festlegen der Eigenschaft.
Kenchilada
3
Dies hat den Vorteil, dass Sie nicht von Refactoring-Fehlern in Resharper getroffen werden, die Ihren Code basierend auf der aktuellen bedingten Einrichtung durcheinander bringen können.
Jafin
3
Ich mag das, aber ich frage mich, warum nicht eine Singleton-Implementierung dafür anstelle eines Dienstes erstellen. Es ist systemspezifisch und macht Ihnen keine Sorgen mehr, dass Sie es überall injizieren müssen. (
Können
1
Ich habe tatsächlich eine Singleton- und Service-Implementierung in einer Klasse, die ich jetzt verwende, sodass Sie die Wahl haben, wie Sie sie verwenden möchten ... Natürlich hat die Service-Implementierung den Vorteil, dass sie einfacher zu "stubben" ist dass Sie beide Codepfade testen können ...
Tod Thomson
Ich frage mich, warum DebuggingServicekeine statische Klasse ist und warum Sie eine Schnittstelle benötigen. Hat dies etwas mit der Verwendung mit einem IoC-Container zu tun?
Ben
23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

Die Methode Debug.Asserthat ein bedingtes Attribut DEBUG. Wenn es nicht definiert ist, wird der Anruf und die Zuordnung isDebug = true werden eliminiert :

Wenn das Symbol definiert ist, ist der Anruf enthalten. Andernfalls wird der Anruf (einschließlich der Auswertung der Parameter des Anrufs) weggelassen.

Wenn DEBUGdefiniert ist, isDebugwird auf gesetzt true(und an übergeben Debug.Assert, was in diesem Fall nichts bewirkt).

AlexD
quelle
Dies ist auch eine ziemlich kreative Lösung. :)
Jack
Nett. Für eine Iterationsvariable, die zwischen Debug und Release wechseln muss ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis
19

Wenn Sie versuchen, die für den Build-Typ definierte Variable zu verwenden, sollten Sie die beiden Zeilen entfernen ...

#define DEBUG  
#define RELEASE 

... dies führt dazu, dass das #if (DEBUG) immer wahr ist.

Außerdem gibt es kein Standard-Symbol für die bedingte Kompilierung für RELEASE . Wenn Sie einen definieren möchten, gehen Sie zu den Projekteigenschaften, klicken Sie auf die Registerkarte Erstellen und fügen Sie dann RELEASE zum Textfeld Bedingte Kompilierungssymbole unter Allgemein hinzu Überschrift .

Die andere Möglichkeit wäre, dies zu tun ...

#if DEBUG
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Release");
#endif
Matthew Whited
quelle
7

Entfernen Sie Ihre Definitionen oben

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

Leicht modifizierte (bastardisierte?) Version der Antwort von Tod Thomson als statische Funktion und nicht als separate Klasse (ich wollte sie in einer WebForm-Ansichtsbindung aus einer Viewutils-Klasse aufrufen können, die ich bereits aufgenommen hatte).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

Stellen Sie sicher, dass Sie die DEBUG-Konstante in den Project Build-Eigenschaften definieren. Dies aktiviert die #if DEBUG. Ich sehe keine vordefinierte RELEASE-Konstante, was bedeuten könnte, dass alles, was sich nicht in einem DEBUG-Block befindet, im RELEASE-Modus ist.

Definieren Sie die DEBUG-Konstante in den Project Build-Eigenschaften

Gridtrak
quelle
5

NameSpace

using System.Resources;
using System.Diagnostics;

Methode

   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;
    }
Ehsan Enaloo
quelle
3

Ein Tipp, der Ihnen viel Zeit sparen kann - vergessen Sie das nicht, auch wenn Sie möchten debug unter Build-Konfiguration (im Menü vs2012 / 13 unter BUILD => CONFIGURATION MANAGER).

Sie müssen auf das PUBLISH Configurationals solches achten :

Geben Sie hier die Bildbeschreibung ein

ilans
quelle
0

Da der Zweck dieser COMPILER-Anweisungen darin besteht, den Compiler anzuweisen, KEINEN Code, Debug-Code, Beta-Code oder möglicherweise Code einzuschließen, der von allen Endbenutzern benötigt wird, mit Ausnahme derjenigen der Werbeabteilung, dh #Define AdDept, die Sie möchten Sie können sie je nach Bedarf einschließen oder entfernen. Ohne Ihren Quellcode ändern zu müssen, wenn beispielsweise ein Nicht-AdDept in das AdDept übergeht. Dann müssen Sie nur noch die Direktive #AdDept in die Eigenschaftenseite der Compileroptionen einer vorhandenen Version des Programms aufnehmen und eine Kompilierung durchführen und wa la! Der Code des zusammengeführten Programms wird lebendig!.

Möglicherweise möchten Sie auch ein Deklarativ für einen neuen Prozess verwenden, der nicht zur Hauptsendezeit bereit ist oder der erst dann im Code aktiv sein kann, wenn es Zeit ist, ihn freizugeben.

Jedenfalls mache ich das so.

mrMagik3805
quelle
0

Ich musste über einen besseren Weg nachdenken. Mir wurde klar, dass # if-Blöcke in anderen Konfigurationen effektiv Kommentare sind (vorausgesetzt DEBUGoder RELEASE; aber wahr mit jedem Symbol)

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");
        }
Hasitha Jayawardana
quelle
0

Entfernen Sie die Definitionen und prüfen Sie, ob sich die Bedingung im Debug-Modus befindet. Sie müssen nicht überprüfen, ob sich die Direktive im Freigabemodus befindet.

Etwas wie das:

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