C # if / then directives pour debug vs release

435

Dans les propriétés de la solution, la configuration est définie sur "version" pour mon seul et unique projet.

Au début de la routine principale, j'ai ce code, et il montre "Mode = Debug". J'ai également ces deux lignes tout en haut:

#define DEBUG 
#define RELEASE

Suis-je en train de tester la bonne variable?

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

Mon objectif est de définir différentes valeurs par défaut pour les variables basées sur le mode débogage vs libération.

NealWalters
la source
13
Vous définissez les DEUX débogage et libération.
Eric Dahlvang

Réponses:

720

DEBUG/ _DEBUGdevrait déjà être défini dans VS.

Supprimez le #define DEBUGdans votre code. Définissez des préprocesseurs dans la configuration de génération pour cette génération spécifique.

La raison pour laquelle il affiche "Mode = Debug" est à cause de votre #define, puis ignore le elif.

La bonne façon de vérifier est:

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

Ne vérifiez pas RELEASE.

psychotik
la source
78
Je voulais ajouter que si l'on voulait seulement vérifier la
3
Pourquoi #ifet non #ifdef?
Bob Stein
23
@ BobStein-VisiBone Rappelez-vous que nous parlons de C # ici, pas C. #ifdefest spécifique au préprocesseur de C / C ++, C # rend obligatoire l'utilisation de #if.
jduncanator
27
@Jess, je crois que c'est Visual Studio qui fait le gris, pas ReSharper
Dakotah Hicock
1
@DakotahHicock C'est exact, je n'utilise pas de resharper et VS grise.
makoshichi
296

Par défaut, Visual Studio définit DEBUG si le projet est compilé en mode Debug et ne le définit pas s'il est en mode Release. RELEASE n'est pas défini par défaut en mode Release. Utilisez quelque chose comme ceci:

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

Si vous voulez faire quelque chose uniquement en mode release:

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

En outre, il convient de souligner que vous pouvez utiliser l' [Conditional("DEBUG")]attribut sur les méthodes qui retournent voidpour les exécuter uniquement si un certain symbole est défini. Le compilateur supprimerait tous les appels à ces méthodes si le symbole n'est pas défini:

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

void Test() {
    PrintLog();
}
Mehrdad Afshari
la source
6
Réponse géniale, appréciée.
Duy Tran
211

Je préfère le vérifier comme ça plutôt que de chercher des #definedirectives:

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

Avec la mise en garde que, bien sûr, vous pouvez compiler et déployer quelque chose en mode débogage mais sans avoir le débogueur attaché.

Joel Coehoorn
la source
1
Je vous remercie! Je ne sais même pas encore ce que sont les "#defines" donc c'est une excellente solution!
Tim
Et dans mon cas, cela fait exactement ce que je veux. En fait, je veux savoir si j'ai un débogueur attaché, parce que je sais que j'ai du code que je ne veux pas exécuter si j'ai un débogueur attaché. C'est génial!
JFTxJ
1
Si personnellement j'aime utiliser #IF DEBUGen situation de débogage du code cela ne devrait pas durer. Pour le code de production, je suis d'accord avec l'utilisation de ce qui précède.
Coops
10
L'inconvénient de faire cela au lieu d'utiliser #DEBUGest que cette instruction if est dans votre code et toujours vérifiée où, comme la #DEBUGréponse supprime le code qui n'est pas applicable au moment de la compilation, vous n'avez donc pas de vérification à l'exécution et votre. exe (ou tout ce que vous compilez) est plus petit.
Dan
1
@ user34660. La réponse à la question posée est "non", ce qui n'aide vraiment personne.
Steve Smith
52

Je ne suis pas un grand fan du truc #if, surtout si vous le répandez tout autour de votre base de code car cela vous posera des problèmes là où les versions de débogage passent, mais les versions de Release échouent si vous ne faites pas attention.

Voici donc ce que j'ai trouvé (inspiré par #ifdef en 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
la source
2
Hé maintenant, c'est assez créatif. J'aime votre utilisation de l'attribut pour définir la propriété.
kenchilada
3
Cela a l'avantage de ne pas être touché par la refactorisation de bogues dans Resharper qui peuvent gâcher votre code en fonction de la configuration conditionnelle actuelle.
Jafin
3
J'aime cela, mais je me demande pourquoi ne pas créer une implémentation singleton pour cela au lieu d'un service. Il est spécifique au système et vous évite d'avoir à vous soucier de l'injecter partout. (pouvez-vous envisager un scénario où la mise en œuvre de cette fonctionnalité serait différente?
BastanteCaro
1
J'ai en fait un singleton et une implémentation de service dans une classe que j'utilise maintenant, donc vous avez le choix de la façon de l'utiliser ... Bien sûr, l'implémentation de service a l'avantage d'être plus facile à "stub" que vous pouvez tester les deux chemins de code ...
Tod Thomson
Je me demande pourquoi DebuggingServicen'est pas une classe statique et pourquoi vous avez besoin d'une interface? Est-ce quelque chose à voir avec son utilisation avec un conteneur IoC?
Ben
23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

La méthode Debug.Asserta un attribut conditionnel DEBUG. S'il n'est pas défini, l'appel et l'affectation isDebug = true sont supprimés :

Si le symbole est défini, l'appel est inclus; sinon, l'appel (y compris l'évaluation des paramètres de l'appel) est omis.

Si DEBUGest défini, isDebugest défini sur true(et transmis à Debug.Assert, ce qui ne fait rien dans ce cas).

AlexD
la source
C'est aussi une solution assez créative. :)
Jack
Agréable. Pour une variable d'itération qui doit changer entre Debug et Release ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis
19

Si vous essayez d'utiliser la variable définie pour le type de build, vous devez supprimer les deux lignes ...

#define DEBUG  
#define RELEASE 

... ceux-ci feront que le #if (DEBUG) sera toujours vrai.

Il n'y a pas non plus de symbole de compilation conditionnelle par défaut pour RELEASE . Si vous souhaitez en définir un, accédez aux propriétés du projet, cliquez sur l' onglet Générer , puis ajoutez RELEASE dans la zone de texte Symboles de compilation conditionnelle sous l'en - tête Général .

L'autre option serait de le faire ...

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

Retirez vos définitions en haut

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

Version légèrement modifiée (bâtarde?) De la réponse de Tod Thomson en tant que fonction statique plutôt que classe distincte (je voulais pouvoir l'appeler dans une liaison WebForm à partir d'une classe viewutils que j'avais déjà incluse).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

Veillez à définir la constante DEBUG dans les propriétés de construction du projet. Cela permettra au #if DEBUG. Je ne vois pas de constante RELEASE prédéfinie, ce qui pourrait impliquer que tout ce qui n'est pas dans un bloc DEBUG est en mode RELEASE.

Définir la constante DEBUG dans les propriétés de construction du projet

gridtrak
la source
5

NameSpace

using System.Resources;
using System.Diagnostics;

Méthode

   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
la source
3

Une astuce qui peut vous faire gagner beaucoup de temps - n'oubliez pas que même si vous choisissez debugsous la configuration de construction (dans le menu vs2012 / 13, c'est sous BUILD => CONFIGURATION MANAGER) - ce n'est pas suffisant.

Vous devez faire attention à la PUBLICATION Configuration, en tant que telle:

entrez la description de l'image ici

ilans
la source
0

Étant donné que le but de ces directives COMPILER est de dire au compilateur de ne PAS inclure de code, de code de débogage, de code bêta ou peut-être de code dont tous vos utilisateurs finaux ont besoin, sauf ceux du service de publicité, c'est-à-dire #Define AdDept que vous souhaitez pouvoir les inclure ou les supprimer en fonction de vos besoins. Sans avoir à changer votre code source si par exemple un non AdDept fusionne dans l'AdDept. Ensuite, tout ce qui doit être fait est d'inclure la directive #AdDept dans la page de propriétés des options du compilateur d'une version existante du programme et de faire une compilation et wa la! le code du programme fusionné prend vie!.

Vous pouvez également vouloir utiliser un déclaratif pour un nouveau processus qui n'est pas prêt pour le prime time ou qui ne peut pas être actif dans le code jusqu'à ce qu'il soit temps de le libérer.

Quoi qu'il en soit, c'est comme ça que je le fais.

mrMagik3805
la source
0

Je dois penser à une meilleure façon. Il m'est apparu que les blocs #if sont effectivement des commentaires dans d'autres configurations (en supposant DEBUGou RELEASE; mais vrai avec n'importe quel symbole)

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
la source
0

Supprimez les définitions et vérifiez si le conditionnel est en mode débogage. Vous n'avez pas besoin de vérifier si la directive est en mode release.

Quelque chose comme ça:

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