C # if / then diretivas para depuração vs release

434

Nas propriedades da solução, tenho a configuração definida como "release" para meu primeiro e único projeto.

No início da rotina principal, eu tenho esse código e está mostrando "Mode = Debug". Eu também tenho essas duas linhas no topo:

#define DEBUG 
#define RELEASE

Estou testando a variável correta?

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

Meu objetivo é definir padrões diferentes para variáveis ​​com base no modo de depuração vs versão.

NealWalters
fonte
13
Você está definindo AMBOS depuração e liberação.
Eric Dahlvang

Respostas:

720

DEBUG/ já _DEBUGdeve estar definido no VS.

Remova o #define DEBUGcódigo. Defina pré-processadores na configuração da construção para essa construção específica.

A razão pela qual ele imprime "Mode = Debug" é por causa do seu #definee então ignora o elif.

A maneira correta de verificar é:

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

Não verifique RELEASE.

psychotik
fonte
78
Eu gostaria de acrescentar que, se alguém quiser apenas checar a versão, pode fazer o seguinte: #if! DEBUG
3
Por que #ife não #ifdef?
Bob Stein
23
@ BobStein-VisiBone Lembre-se de que estamos falando de C # aqui, não C. #ifdefé específico para o pré-processador de C / C ++, o C # exige o uso de #if.
jduncanator
27
@Jess, eu acredito que este é o Visual Studio fazendo o grisalho para fora, não ReSharper
Dakotah Hicock
1
@DakotahHicock Isso está correto, eu não uso o ressharper e o VS esmaece.
precisa saber é o seguinte
295

Por padrão, o Visual Studio define DEBUG se o projeto é compilado no modo Debug e não o define se estiver no modo Release. RELEASE não está definido no modo Release por padrão. Use algo como isto:

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

Se você quiser fazer algo apenas no modo de lançamento:

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

Além disso, vale ressaltar que você pode usar o [Conditional("DEBUG")]atributo em métodos que retornam voidpara executá-los apenas se um determinado símbolo estiver definido. O compilador removeria todas as chamadas para esses métodos se o símbolo não estiver definido:

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

void Test() {
    PrintLog();
}
Mehrdad Afshari
fonte
6
Resposta incrível, apreciada.
precisa saber é o seguinte
211

Eu prefiro verificá-lo assim do que procurar #definediretivas:

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

Com a ressalva de que, é claro, você pode compilar e implantar algo no modo de depuração, mas ainda não tem o depurador conectado.

Joel Coehoorn
fonte
1
Obrigado! Ainda nem sei o que são "#defines", então essa é uma ótima solução!
Tim
E no meu caso, isso faz exatamente o que eu quero. Na verdade, quero saber se tenho um depurador conectado, porque sei que tenho algum código que não quero que seja executado se tiver um depurador conectado. Isso é incrível!
JFTxJ 13/08
1
Se pessoalmente gosta de usar #IF DEBUGem situação de código de depuração que não deve durar. Para o código de produção, concordo com o uso acima.
Coops
10
A desvantagem de fazer isso em vez de usar #DEBUGé que esta instrução if está no seu código e sempre é verificada onde, como a #DEBUGresposta remove o código que não é aplicável no tempo de compilação, para que você não tenha uma verificação em tempo de execução e sua. exe (ou o que você compilar) é menor.
Dan
1
@ user34660. A resposta para a pergunta declarada é "não", o que realmente não ajuda ninguém.
21819 Steve Steve
52

Eu não sou um grande fã do material #if, especialmente se você o espalhar por toda a sua base de código, pois isso causará problemas nos quais as construções de depuração passam, mas as versões de liberação falham se você não tomar cuidado.

Então, aqui está o que eu criei (inspirado em #ifdef em 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
fonte
2
Ei, agora, isso é bastante criativo. Eu gosto do seu uso do atributo para definir a propriedade.
kenchilada
3
Isso tem a vantagem de não ser atingido pela refatoração de erros no Resharper que podem atrapalhar seu código com base na configuração condicional atual.
Jafin 01/04
3
Eu gosto disso, mas eu estou querendo saber por que não criar uma implementação singleton para isso em vez de um serviço. É específico do sistema e impede que você se preocupe em injetá-lo em qualquer lugar. (você pode imaginar um cenário em que a implementação dessa funcionalidade seria diferente?
BastanteCaro
1
Na verdade, eu tenho uma implementação de serviço e singleton em uma classe que estou usando agora, para que você possa escolher de que maneira usá-lo ... É claro que a implementação do serviço tem o benefício de ser mais fácil "stub" que você pode testar ambos os caminhos de código ...
Tod Thomson
Gostaria de saber por que DebuggingServicenão é uma classe estática e por que você precisa de uma interface? Isso tem algo a ver com usar isso com um contêiner de IoC?
Ben
23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

O método Debug.Asserttem atributo condicional DEBUG. Se não estiver definido, a chamada e a atribuição isDebug = true são eliminadas :

Se o símbolo estiver definido, a chamada será incluída; caso contrário, a chamada (incluindo a avaliação dos parâmetros da chamada) é omitida.

Se DEBUGfor definido, isDebugé definido como true(e passado para Debug.Assert, o que não faz nada nesse caso).

AlexD
fonte
Essa também é uma solução bastante criativa. :)
Jan
Agradável. Para uma variável de iteração que precisa mudar entre depuração e lançamento ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis
19

Se você estiver tentando usar a variável definida para o tipo de construção, remova as duas linhas ...

#define DEBUG  
#define RELEASE 

... isso fará com que o #if (DEBUG) seja sempre verdadeiro.

Também não há um símbolo de compilação condicional padrão para RELEASE . Se você deseja definir uma, vá para as propriedades do projeto, clique no botão Build guia e adicione RELEASE à caixa de texto Símbolos de compilação condicional, sob o cabeçalho Geral .

A outra opção seria fazer isso ...

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

Remova suas definições na parte superior

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

Versão ligeiramente modificada (bastardizada?) Da resposta de Tod Thomson como uma função estática, em vez de uma classe separada (eu queria poder chamá-la em uma vinculação de exibição do WebForm de uma classe de viewutils que eu já havia incluído).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

Certifique-se de definir a constante DEBUG nas propriedades de criação do projeto. Isso ativará o #if DEBUG. Não vejo uma constante RELEASE predefinida, o que poderia implicar que qualquer coisa que não esteja em um bloco DEBUG seja o modo RELEASE.

Definir constante DEBUG nas propriedades de criação do projeto

gridtrak
fonte
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
fonte
3

Uma dica que pode economizar muito tempo - não esqueça que, mesmo se você escolher debug na configuração de compilação (no menu vs2012 / 13, está em BUILD => CONFIGURATION MANAGER) - isso não é suficiente.

Você precisa prestar atenção ao PUBLISH Configuration, como tal:

insira a descrição da imagem aqui

ilans
fonte
0

Como o objetivo dessas diretrizes do COMPILER é instruir o compilador a NÃO incluir código, código de depuração, código beta ou talvez o código necessário para todos os seus usuários finais, exceto os do departamento de publicidade, por exemplo, #Define AdDept que você deseja poderá incluí-los ou removê-los com base nas suas necessidades. Sem ter que alterar seu código-fonte se, por exemplo, um AdDept não for mesclado ao AdDept. Então, tudo o que precisa ser feito é incluir a diretiva #AdDept na página de propriedades das opções do compilador de uma versão existente do programa e fazer uma compilação e pronto! o código do programa mesclado ganha vida !.

Você também pode usar um declarativo para um novo processo que não está pronto para o horário nobre ou que não pode estar ativo no código até a hora de liberá-lo.

De qualquer forma, é assim que eu faço.

mrMagik3805
fonte
0

Eu comecei a pensar em uma maneira melhor. Percebi que os blocos #if são efetivamente comentários em outras configurações (assumindo DEBUGou RELEASE; mas verdadeiro com qualquer 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
fonte
0

Remova as definições e verifique se o condicional está no modo de depuração. Você não precisa verificar se a diretiva está no modo de liberação.

Algo assim:

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