C#if / then调试和发布指令


432

在“解决方案”属性中,对于我的唯一一个项目,我将“配置”设置为“发布”。

在主例程的开头,我有以下代码,并且显示“ Mode = Debug”。我在最上方也有这两行:

#define DEBUG 
#define RELEASE

我在测试正确的变量吗?

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

我的目标是根据调试与发布模式为变量设置不同的默认值。


13
您正在定义调试和发布。
埃里克·达赫郎

Answers:


718

DEBUG/ _DEBUG应该已经在VS中定义了。

删除#define DEBUG代码中的。在该特定构建的构建配置中设置预处理器。

打印“ Mode = Debug”的原因是由于您的原因#define,然后跳过elif

正确的检查方法是:

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

不要检查RELEASE


77
我想补充一下,如果只想检查RELEASE,则可以执行以下操作:#if!DEBUG

3
为什么#if#ifdef呢?
鲍勃·斯坦

23
@ BobStein-VisiBone记住,我们在这里谈论的是C#,而不是C. #ifdef是特定于C / C ++的预处理器的,C#强制使用#if
jduncanator 2014年

27
@Jess,我相信这是Visual Studio进行的变灰,而不是ReSharper
Dakotah Hicock

1
@DakotahHicock没错,我不使用Resharper,而VS将其变灰。
makoshichi

294

默认情况下,如果项目是在Debug模式下编译的,则Visual Studio会定义DEBUG,而在Release模式下则不会定义它。默认情况下,未在发布模式下定义RELEASE。使用这样的东西:

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

如果您只想在发布模式下做某事:

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

另外,值得指出的是,可以[Conditional("DEBUG")]在返回的方法上使用属性,void以使它们仅在定义了特定符号的情况下才执行。如果未定义符号,则编译器将删除对这些方法的所有调用:

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

void Test() {
    PrintLog();
}

6
很棒的答案,感激不尽。
Duy Tran

210

我喜欢这样检查它而不是寻找#define指令:

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

有了警告,您当然可以在调试模式下编译和部署某些东西,但仍然没有附加调试器。


1
谢谢!我什至不知道“ #defines”是什么,所以这是一个很好的解决方案!
蒂姆(Tim)

就我而言,这正是我想要的。我实际上想知道是否连接了调试器,因为我知道如果连接了调试器,我不想执行某些代码。这太棒了!
JFTxJ 2013年

1
如果个人喜欢#IF DEBUG在调试代码不应该持续的情况下使用。对于生产代码,我同意使用上述代码。
Coops

10
这样做而不是使用的缺点#DEBUG是,此if语句位于您的代码中,并始终检查#DEBUG答案是否删除了在编译时不适用的代码,因此您没有运行时检查和your。 exe(或您编译的任何文件)较小。
2014年

1
@ user34660。陈述的问题的答案是“否”,这实际上并没有帮助任何人。
史蒂夫·史密斯,

51

我不是#if东西的忠实拥护者,特别是如果将其分散在代码库中,因为如果您不小心,它将在Debug生成通过的地方给您带来问题,但是Release生成会失败。

因此,这就是我的想法(受C#中#ifdef启发):

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
嘿,这很有创意。我喜欢您使用属性来设置属性。
kenchilada

3
这样做的好处是不会因重构Resharper中的错误而受到打击,这些错误会根据当前的条件设置使您的代码混乱。
2013年

3
我喜欢这个,但是我想知道为什么不为此创建一个单例实现而不是一个服务。它是特定于系统的,它使您不必担心将其注入到各处。(您是否可以设想此功能的实现会有所不同的方案?
BastanteCaro 2015年

1
实际上,我现在正在使用一个类中的单例和服务实现,因此您可以选择使用它的方式...当然,服务实现的好处是更容易“存根”,因此您可以测试两个代码路径...
Tod Thomson

我想知道为什么DebuggingService不是静态类,为什么需要接口?这与将IoC容器一起使用有关吗?
2016年

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

该方法Debug.Assert具有条件属性DEBUG。如果未定义,则消除呼叫和分配isDebug = true

如果定义了该符号,则包括该呼叫;否则,将忽略该呼叫(包括对呼叫参数的评估)。

如果DEBUG定义了if ,isDebug则将其设置为true(并传递给Debug.Assert,在这种情况下不执行任何操作)。


这也是一个非常有创意的解决方案。:)
杰克

真好 对于需要在Debug和Release之间进行更改的迭代变量... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis

19

如果您尝试使用为构建类型定义的变量,则应删除两行...

#define DEBUG  
#define RELEASE 

...这些将导致#if(DEBUG)始终为true。

也没有RELEASE的默认条件编译符号。如果要定义一个转到项目属性,请单击“ 生成”选项卡,然后将“发布”添加到“ 常规”标题下的“ 条件编译符号”文本框中。

另一个选择是执行此操作...

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

7

删除顶部的定义

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

7

托德·汤姆森(Tod Thomson)对答案的略作修改(受重创?)版本是一个静态函数,而不是一个单独的类(我希望能够从我已经包含的viewutils类的WebForm视图绑定中调用它)。

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

    WellAreWe(ref debugging);

    return debugging;
}

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

6

确保在“项目构建”属性中定义DEBUG常量。这将启用#if DEBUG。我没有看到预定义的RELEASE常量,所以这可能意味着不在DEBUG块中的任何内容都是RELEASE模式。

在项目构建属性中定义DEBUG常量


5

命名空间

using System.Resources;
using System.Diagnostics;

方法

   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

一条可以为您节省大量时间的提示-即使您选择debug在构建配置下(在vs2012 / 13菜单上,它位于BUILD => CONFIGURATION MANAGER下),也不要忘记-这还不够。

您需要注意PUBLISH Configuration,例如:

在此处输入图片说明


0

由于这些COMPILER指令的目的是告诉编译器不要包括代码,调试代码,beta代码或所有最终用户所需的代码,除了广告部门(即您想要的#Define AdDept)外能够根据需要添加或删除它们。例如,如果非AdDept合并到AdDept中,则无需更改您的源代码。然后,所有需要做的就是在程序的现有版本的编译器选项属性页中包含#AdDept指令,并进行编译和警告!合并后的程序代码会自动运行!

您可能还想对新程序使用声明,而该声明在黄金时间还没有准备好,或者直到需要释放它时才在代码中处于活动状态。

无论如何,这就是我的方式。


0

我必须考虑一种更好的方法。我突然意识到#if块在其他配置中实际上是注释(假设DEBUGRELEASE;但是对任何符号都适用)

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

删除定义,然后检查条件是否处于调试模式。您无需检查指令是否处于释放模式。

像这样:

#if DEBUG
     Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.