C # directivas if / then para depuración vs lanzamiento

435

En las propiedades de la Solución, tengo la Configuración establecida en "lanzamiento" para mi único proyecto.

Al comienzo de la rutina principal, tengo este código y muestra "Mode = Debug". También tengo estas dos líneas en la parte superior:

#define DEBUG 
#define RELEASE

¿Estoy probando la variable correcta?

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

Mi objetivo es establecer diferentes valores predeterminados para las variables basadas en el modo de depuración vs liberación.

NealWalters
fuente
13
Está definiendo AMBAS depuración y liberación.
Eric Dahlvang

Respuestas:

720

DEBUG/ _DEBUGdebería estar definido en VS ya.

Elimine el #define DEBUGen su código. Establezca preprocesadores en la configuración de compilación para esa compilación específica.

La razón por la que imprime "Mode = Debug" se debe a tu #definey luego omite el elif.

La forma correcta de verificar es:

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

No lo revises RELEASE.

psicotik
fuente
78
Quería agregar que si uno solo quería verificar la LIBERACIÓN, entonces se puede hacer esto: #if! DEBUG
3
¿Por qué #ify no #ifdef?
Bob Stein
23
@ BobStein-VisiBone Recuerde que estamos hablando de C # aquí, no C. #ifdefes específico del preprocesador de C / C ++, C # exige el uso de #if.
jduncanator
27
@Jess, creo que esto es Visual Studio haciendo el gris, no ReSharper
Dakotah Hicock
1
@DakotahHicock Eso es correcto, no uso resharper y VS lo atenúa.
makoshichi
296

De forma predeterminada, Visual Studio define DEBUG si el proyecto se compila en modo Debug y no lo define si está en modo Release. RELEASE no está definido en el modo Release por defecto. Usa algo como esto:

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

Si solo quieres hacer algo en el modo de lanzamiento:

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

Además, vale la pena señalar que puede usar el [Conditional("DEBUG")]atributo en los métodos que vuelven voida ejecutarse solo si se define un determinado símbolo. El compilador eliminaría todas las llamadas a esos métodos si el símbolo no está definido:

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

void Test() {
    PrintLog();
}
Mehrdad Afshari
fuente
66
Impresionante respuesta, apreciada.
Duy Tran
211

Prefiero comprobarlo así que buscar #definedirectivas:

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

Con la advertencia de que, por supuesto, podría compilar e implementar algo en modo de depuración, pero aún no tiene el depurador conectado.

Joel Coehoorn
fuente
1
¡Gracias! Aún no sé qué son "#defines", ¡así que esta es una gran solución!
Tim
Y en mi caso, esto hace exactamente lo que quiero. De hecho, quiero saber si tengo un depurador conectado, porque sé que tengo algún código que no quiero que se ejecute si tengo un depurador conectado. ¡Esto es asombroso!
JFTxJ
1
Si personalmente le gusta usar #IF DEBUGen una situación de código de depuración que no debería durar. Para el código de producción, estoy de acuerdo con el uso de lo anterior.
Coops
10
La desventaja de hacer esto en lugar de usar #DEBUGes que esta declaración if está en su código y siempre verifica dónde, ya que la #DEBUGrespuesta elimina el código que no es aplicable en el momento de la compilación, por lo que no tiene una verificación de tiempo de ejecución y su. exe (o lo que sea que compiles) es más pequeño.
Dan
1
@ user34660. La respuesta a la pregunta planteada es "no", lo que realmente no ayuda a nadie.
Steve Smith
52

No soy un gran admirador de las cosas #if, especialmente si lo distribuye por toda la base de su código, ya que le dará problemas donde las compilaciones de Debug pasan pero las compilaciones de Release fallan si no tiene cuidado.

Entonces, esto es lo que se me ocurrió (inspirado en #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
fuente
2
Hola, eso es bastante creativo. Me gusta su uso del atributo para establecer la propiedad.
kenchilada
3
Esto tiene la ventaja de no ser golpeado por la refactorización de errores en Resharper que pueden estropear su código en función de la configuración condicional actual.
Jafin 01 de
3
Me gusta esto, pero me pregunto por qué no crear una implementación singleton para esto en lugar de un servicio. Es específico del sistema y evita que tenga que preocuparse por inyectarlo en todas partes. (¿puede imaginar un escenario donde la implementación de esta funcionalidad sería diferente?
BastanteCaro
1
De hecho, tengo una implementación de servicio y singleton en una clase que estoy usando ahora para que pueda elegir la forma de usarla ... Por supuesto, la implementación del servicio tiene el beneficio de ser más fácil de eliminar. que puede probar ambas rutas de código ...
Tod Thomson
Me pregunto por qué DebuggingServiceno es una clase estática y por qué necesita una interfaz. ¿Tiene esto algo que ver con usar esto con un contenedor de IoC?
Ben
23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

El método Debug.Asserttiene atributo condicional DEBUG. Si no está definido, la llamada y la asignación isDebug = true se eliminan :

Si se define el símbolo, se incluye la llamada; de lo contrario, se omite la llamada (incluida la evaluación de los parámetros de la llamada).

Si DEBUGse define, isDebugse establece en true(y se pasa a Debug.Assert, que no hace nada en ese caso).

AlexD
fuente
Esta también es una solución bastante creativa. :)
Jack
Agradable. Para una variable de iteración que necesita cambiar entre Debug y Release ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis
19

Si está intentando utilizar la variable definida para el tipo de compilación, debe eliminar las dos líneas ...

#define DEBUG  
#define RELEASE 

... esto hará que #if (DEBUG) sea ​​siempre verdadero.

Además, no hay un símbolo de compilación condicional predeterminado para RELEASE . Si desea definir uno, vaya a las propiedades del proyecto, haga clic en la pestaña Generar y luego agregue LIBERACIÓN al cuadro de texto Símbolos de compilación condicional bajo el encabezado General .

La otra opción sería hacer esto ...

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

Elimina tus definiciones en la parte superior

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

Versión ligeramente modificada (¿bastarda?) De la respuesta de Tod Thomson como una función estática en lugar de una clase separada (quería poder llamarla en un enlace de vista WebForm desde una clase viewutils que ya había incluido).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

Asegúrese de definir la constante DEPURACIÓN en las Propiedades de compilación del proyecto. Esto habilitará el #if DEBUG. No veo una constante LIBERACIÓN predefinida, por lo que eso podría implicar que cualquier cosa que no esté en un bloque DEPURACIÓN es el modo LIBERACIÓN.

Defina la constante DEBUG en las propiedades de construcción del proyecto

gridtrak
fuente
5

NameSpace

using System.Resources;
using System.Diagnostics;

Método

   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
fuente
3

Un consejo que puede ahorrarle mucho tiempo; no lo olvide, incluso si elige debug en la configuración de compilación (en el menú vs2012 / 13 está en BUILD => CONFIGURATION MANAGER), eso no es suficiente.

Debe prestar atención a PUBLISH Configuration, como tal:

ingrese la descripción de la imagen aquí

ilans
fuente
0

Dado que el propósito de estas directivas del COMPILADOR es decirle al compilador que NO incluya código, código de depuración, código beta o tal vez el código que necesitan todos sus usuarios finales, excepto los del departamento de publicidad, es decir, #Definir AdDept que desea podrá incluirlos o eliminarlos según sus necesidades. Sin tener que cambiar su código fuente si, por ejemplo, un AdDept no se fusiona con el AdDept. Entonces, todo lo que debe hacerse es incluir la directiva #AdDept en la página de propiedades de opciones del compilador de una versión existente del programa y hacer una compilación y ¡wa la! ¡El código del programa combinado sale vivo!

También es posible que desee utilizar una declaración para un nuevo proceso que no esté listo para el horario de máxima audiencia o que no pueda estar activo en el código hasta que sea el momento de lanzarlo.

De todos modos, así es como lo hago.

mrMagik3805
fuente
0

Me puse a pensar en una mejor manera. Me di cuenta de que los bloques #if son comentarios efectivos en otras configuraciones (suponiendo DEBUGo RELEASE; pero cierto con cualquier símbolo)

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
fuente
0

Elimine las definiciones y compruebe si el condicional está en modo de depuración. No necesita verificar si la directiva está en modo de liberación.

Algo como esto:

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