【问题标题】:C# if/then directives for debug vs release用于调试与发布的 C# if/then 指令
【发布时间】:2011-01-07 10:15:13
【问题描述】:

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

在主程序的开头,我有这段代码,它显示“Mode=Debug”。 我在最顶部也有这两行:

#define DEBUG 
#define RELEASE

我是否在测试正确的变量?

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

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

【问题讨论】:

  • 您正在定义调试和发布。

标签: c# debugging release compiler-directives


【解决方案1】:

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

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

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

正确的检查方法是:

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

不要检查RELEASE。

【讨论】:

  • 我想补充一点,如果只想检查 RELEASE,那么可以这样做:#if !DEBUG
  • 为什么是#if 而不是#ifdef?
  • @BobStein-VisiBone 请记住,我们在这里讨论的是 C#,而不是 C。#ifdef 特定于 C/C++ 的预处理器,C# 要求使用 #if。
  • @Jess,我相信这是 Visual Studio 做的变灰,而不是 ReSharper
  • 如何“设置预处理器”?
【解决方案2】:

默认情况下,如果项目在 Debug 模式下编译,Visual Studio 会定义 DEBUG,如果它处于 Release 模式,则不会定义它。默认情况下,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();
}

【讨论】:

  • 很棒的答案,感谢。
【解决方案3】:

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

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

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

【讨论】:

  • 谢谢!我什至还不知道“#defines”是什么,所以这是一个很好的解决方案!
  • 我的情况是,这正是我想要的。我实际上想知道我是否附加了调试器,因为我知道如果我附加了调试器,我不想执行一些代码。这太棒了!
  • 如果个人喜欢在调试不应该持续的代码的情况下使用#IF DEBUG。对于生产代码,我同意使用上述内容。
  • 这样做而不是使用 #DEBUG 的缺点是这个 if 语句在你的代码中,并且总是检查 #DEBUG 答案在哪里删除了在编译时不适用的代码所以你没有运行时检查,你的 .exe(或你编译的任何东西)更小。
  • @user34660。上述问题的答案是“不”,这对任何人都没有帮助。
【解决方案4】:

我不是#if 东西的忠实拥护者,特别是如果你将它散布在你的代码库中,因为如果你不小心,它会给你带来调试构建通过但发布构建失败的问题。

这就是我想出的(灵感来自#ifdef in 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;
    }
}

【讨论】:

  • 嘿,这很有创意。我喜欢你使用属性来设置属性。
  • 这样做的好处是不会受到 Resharper 中的重构错误的影响,这些错误可能会根据当前的条件设置弄乱您的代码。
  • 我喜欢这个,但我想知道为什么不为此创建一个单例实现而不是一个服务。它是系统特定的,它使您不必担心到处注入它。 (你能想象这个功能的实现会有什么不同的场景吗?
  • 我实际上在我现在使用的一个类中有一个单例和服务实现,因此您可以选择使用它的方式...当然,服务实现的好处是更容易“存根”,以便您可以测试两个代码路径...
  • 我想知道为什么DebuggingService 不是静态类,为什么需要接口?这与将其与 IoC 容器一起使用有关吗?
【解决方案5】:
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

方法Debug.Assert 具有条件属性DEBUG。如果未定义,则调用和赋值isDebug = true为eliminated:

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

如果定义了DEBUG,则isDebug 设置为true(并传递给Debug.Assert,在这种情况下什么都不做)。

【讨论】:

  • 这也是一个非常有创意的解决方案。 :)
  • 不错。对于需要在 Debug 和 Release 之间更改的迭代变量...var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
【解决方案6】:

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

#define DEBUG  
#define RELEASE 

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

RELEASE 也没有默认的条件编译符号。如果你想定义一个去项目属性,点击Build选项卡,然后在General下的Conditional compilation symbols文本框中添加RELEASE em> 标题。

另一种选择是这样做......

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

【讨论】:

    【解决方案7】:

    请务必在项目构建属性中定义 DEBUG 常量。这将启用#if DEBUG。我没有看到预定义的 RELEASE 常量,因此这可能意味着任何不在 DEBUG 块中的东西都是 RELEASE 模式。

    【讨论】:

      【解决方案8】:

      删除顶部的定义

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

      【讨论】:

        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          命名空间

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

          【讨论】:

            【解决方案11】:

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

            您需要关注PUBLISH Configuration,如:

            【讨论】:

              【解决方案12】:

              这里值得注意的是,基于#if DEBUG 和if(System.Diagnostics.Debugger.IsAttached) 的条件执行代码之间最显着的区别之一是编译器指令更改了编译的代码。也就是说,如果您在 #if DEBUG/#else/#endif 条件块中有两个不同的语句,则只有 一个 会出现在编译代码中。这是一个重要的区别,因为它允许您执行诸如有条件地将方法定义编译为 public void mymethod() 与 internal void mymethod() 之类的操作,具体取决于构建类型,这样您就可以在不会中断访问的调试构建上运行单元测试控制生产构建,或有条件地编译调试构建中的辅助函数,如果它们在逃逸时会以某种方式违反安全性,则不会出现在最终代码中。另一方面,IsAttached 属性不会影响已编译的代码。两组代码都在所有构建中 - IsAttached 条件只会影响执行的内容。这本身可能会带来安全问题。

              【讨论】:

                【解决方案13】:

                我不得不考虑一个更好的方法。我突然意识到#if 块在其他配置中实际上是 cmets(假设 DEBUG 或 RELEASE;但对于任何符号都是如此)

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

                【讨论】:

                  【解决方案14】:

                  删除定义并检查条件是否处于调试模式。您不需要检查指令是否处于发布模式。

                  类似这样的:

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

                  【讨论】:

                    【解决方案15】:

                    由于这些 COMPILER 指令的目的是告诉编译器不要包含代码、调试代码、beta 代码,或者可能是所有最终用户所需的代码,广告部门除外,即#Define AdDept您希望能够根据您的需要包含或删除它们。例如,如果非 AdDept 合并到 AdDept 中,则无需更改源代码。然后需要做的就是在现有版本的程序的编译器选项属性页面中包含#AdDept 指令,然后编译并哇!合并后的程序代码活了起来!

                    您可能还希望对尚未准备好迎接黄金时间或在发布之前无法在代码中处于活动状态的新进程使用声明性。

                    不管怎样,我就是这样做的。

                    【讨论】:

                      猜你喜欢
                      • 2011-03-26
                      • 2018-06-29
                      • 1970-01-01
                      • 1970-01-01
                      • 2023-04-08
                      • 2017-05-02
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-05-09
                      相关资源
                      最近更新 更多