用于调试和发布的c# if/then指令

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

在主例程的开头,我有这段代码,它显示“Mode=Debug”。 在最上面还有这两行:

#define DEBUG
#define RELEASE

我测试的变量对吗?

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

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

440719 次浏览

如果您试图使用为构建类型定义的变量,您应该删除这两行…

#define DEBUG
#define RELEASE

... 这将导致#如果(调试)始终为真。

此外,释放也没有默认的条件编译符号。如果你想定义一个转到项目属性,单击构建选项卡,然后将RELEASE添加到一般标题下的条件编译符号文本框中。

另一个选择是这样做……

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

默认情况下,如果项目在调试模式下编译,Visual Studio定义DEBUG,如果项目在发布模式下编译,则不定义DEBUG。默认情况下,RELEASE模式中没有定义RELEASE。可以这样说:

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

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

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

此外,值得指出的是,你可以在返回void的方法上使用[Conditional("DEBUG")]属性,以便只有在定义了某个符号时才执行它们。如果符号没有定义,编译器将删除对这些方法的所有调用:

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


void Test() {
PrintLog();
}

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

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

它打印“Mode=Debug”的原因是因为你的#define,然后跳过elif

正确的检查方法是:

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

不要检查RELEASE

删除顶部的定义

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

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

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

需要注意的是,您当然可以在调试模式下编译和部署一些东西,但仍然没有附加调试器。

名称空间

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;
}

我不是#if之类的东西的超级粉丝,特别是如果你把它散布在你的代码库中,因为如果你不小心,它会给你带来调试构建通过但发布构建失败的问题。

所以这里是我想出的(受到#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;
}
}

因为这些COMPILER指令的目的是告诉编译器不要包含代码,调试代码,beta代码,或者可能是所有最终用户需要的代码,除了广告部门,也就是#定义AdDept,你想要根据你的需要包括或删除它们。如果一个非AdDept合并到AdDept,则无需更改源代码。然后所有需要做的就是在现有版本的程序的编译器选项属性页中包含#AdDept指令,并进行编译和wa la!合并后的程序代码是活的!

对于还没有准备好进入黄金时段的新流程,或者在发布之前不能在代码中活动的新流程,您可能还想使用声明式。

总之,我就是这么做的。

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

方法Debug.Assert具有条件属性DEBUG。如果没有定义,还有作业 isDebug = true调用为消除:

如果定义了符号,则包含调用;否则,调用(包括调用参数的计算)将被省略。

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

对Tod Thomson的答案稍加修改(私生子化?),将其作为一个静态函数而不是一个单独的类(我希望能够从我已经包含的viewutils类中调用它)。

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


WellAreWe(ref debugging);


return debugging;
}


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

一个可以节省你很多时间的技巧——不要忘记,即使你在构建配置下选择debug(在vs2012/13菜单中,它在build => configuration MANAGER下)——这是不够的。

你需要注意PUBLISH Configuration,就像这样:

enter image description here

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

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

我得想个更好的办法。我突然意识到,#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");
}

删除定义并检查条件是否处于调试模式。你不需要检查指令是否处于释放模式。

就像这样:

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

这里值得注意的是,基于#if DEBUGif(System.Diagnostics.Debugger.IsAttached)的有条件执行代码之间最重要的区别之一是编译器指令更改已编译的代码。也就是说,如果在#if DEBUG/#else/#endif条件块中有两个不同的语句,那么在编译后的代码中只会出现其中的一个条语句。这是一个重要的区别,因为它允许你做一些事情,比如根据构建类型有条件地将方法定义编译为public void mymethod()internal void mymethod(),这样你就可以,例如,在调试构建上运行单元测试,不会破坏生产构建上的访问控制,或者在调试构建中有条件地编译helper函数,如果它们在某种程度上违反安全性,如果它们逃逸到野外,将不会出现在最终代码中。另一方面,IsAttached属性不影响编译后的代码。这两组代码都存在于所有构建中——IsAttached条件只会影响执行。这本身就会带来安全问题。