#if DEBUG vs.条件("DEBUG")

Luc*_*s B 416 c# debugging preprocessor debug-symbols

在大型项目中使用哪个更好,为什么更好:

#if DEBUG
    public void SetPrivateValue(int value)
    { ... }
#endif
Run Code Online (Sandbox Code Playgroud)

要么

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Run Code Online (Sandbox Code Playgroud)

m-y*_*m-y 558

这真的取决于你的目标:

  • #if DEBUG:这里的代码甚至不会在发布时到达IL.
  • [Conditional("DEBUG")]:这个代码将到达IL,但是呼叫,除非当呼叫者被编译DEBUG设置将省略该方法.

我个人根据情况使用两者:

条件("DEBUG")示例:我使用它,以便我不必在发布期间返回并编辑我的代码,但在调试期间我想确保我没有进行任何拼写错误.当我尝试在INotifyPropertyChanged中使用它时,此函数会检查我是否正确输入了属性名称.

[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
            GetType(), propertyName));
}
Run Code Online (Sandbox Code Playgroud)

你真的不想创建一个函数,#if DEBUG除非你愿意用相同的函数包装每个函数的调用#if DEBUG:

#if DEBUG
    public void DoSomething() { }
#endif

    public void Foo()
    {
#if DEBUG
        DoSomething(); //This works, but looks FUGLY
#endif
    }
Run Code Online (Sandbox Code Playgroud)

与:

[Conditional("DEBUG")]
public void DoSomething() { }

public void Foo()
{
    DoSomething(); //Code compiles and is cleaner, DoSomething always
                   //exists, however this is only called during DEBUG.
}
Run Code Online (Sandbox Code Playgroud)

#if DEBUG示例:我在尝试为WCF通信设置不同的绑定时使用它.

#if DEBUG
        public const String ENDPOINT = "Localhost";
#else
        public const String ENDPOINT = "BasicHttpBinding";
#endif
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,代码全部存在,但只是被忽略,除非打开DEBUG.在第二个示例中,const ENDPOINT设置为"Localhost"或"BasicHttpBinding",具体取决于是否设置了DEBUG.


更新:我正在更新这个答案,以澄清一个重要而棘手的问题.如果选择使用ConditionalAttribute,请记住在编译期间省略了调用,而不是运行时.那是:

MyLibrary.dll

[Conditional("DEBUG")]
public void A()
{
    Console.WriteLine("A");
    B();
}

[Conditional("DEBUG")]
public void B()
{
    Console.WriteLine("B");
}
Run Code Online (Sandbox Code Playgroud)

当库是针对发布模式编译的(即没有DEBUG符号)时,它将永远具有B()A()省略内的调用,即使A()包含调用,因为在调用程序集中定义了DEBUG.

  • #if Debug for DoSomething不需要包含#if DEBUG所包含的所有调用语句.你可以1:只是#if DEBUG在DoSomething里面,或者用一个空白的DoSomething定义#else.你的评论仍然有助于我理解其中的差异,但#if DEBUG并不像你所展示的那样难看. (12认同)
  • 如果有人想知道,IL =中级语言 - https://en.wikipedia.org/wiki/Common_Intermediate_Language (5认同)
  • 如果只是#if DEBUG的内容,当代码在非调试版本中运行时,JIT可能仍然包含对函数的调用.使用Conditional属性意味着JIT知道在非DEBUG构建中甚至不输出调用点. (3认同)
  • @JeffYates:我不知道你写的是和我解释的有什么不同. (2认同)

Jon*_*eet 63

嗯,值得注意的是,它们并不意味着完全相同.

如果未定义DEBUG符号,则在第一种情况下SetPrivateValue将不会调用自身...而在第二种情况下它将存在,但是在没有DEBUG符号的情况下编译的任何调用者将省略这些调用.

如果代码及其所有来电号码在同一装配这种差异是不太重要的-但它意味着,在第一种情况下,你需要有#if DEBUG各地的调用代码.

就个人而言,我建议采用第二种方法 - 但你确实需要保持它们之间的区别.

  • 调用代码的+1也需要有#if语句.这意味着#if语句将会激增...... (5认同)

Jim*_*ffa 43

我肯定会有很多人不同意我的看法,但是花了很多时间作为一个不停地听到"但它适用于我的机器!"的构建人,我认为你应该从不使用它们.如果您确实需要一些测试和调试,请找出一种方法,使该可测试性与实际生产代码分开.

在单元测试中使用模拟进行抽象的场景,为要测试的一个场景制作一个关闭版本的东西,但是不要将调试测试放入为测试和编写用于生产版本的二进制文件的代码中.这些调试测试只是隐藏了开发人员可能存在的错误,因此在此过程的后期才能找到它们.

  • 我通常会同意你的意见,但如果你处于性能至关重要的情况,那么你不希望用无关的日志记录和用户输出来混淆代码,但我100%同意它们不应该被用来改变基本行为 (6认同)
  • -1使用其中任何一个都没有错.声明单元测试和DI以某种方式取代了调试启用的产品构建是天真的. (5认同)
  • 我完全同意你的看法.如果您正在使用DI和模拟测试,为什么在代码中需要`#if debug`或任何类似的构造? (4认同)
  • 我们经常做一些事情,比如在调试版本中使用`#if DEBUG`设置默认的收件人电子邮件,以便我们在测试必须在过程中传输电子邮件的系统时不会意外地发送垃圾邮件. .有时这些是工作的正确工具:) (4认同)

sof*_*ntp 13

这个也很有用:

if (Debugger.IsAttached)
{
...
}
Run Code Online (Sandbox Code Playgroud)

  • 就我个人而言,我不认为这与其他两种替代方案相比有何用处。这保证了整个块被编译,并且即使在发布版本中也必须在运行时调用“Debugger.IsAttached”。 (4认同)

P D*_*ddy 9

与第一示例中,SetPrivateValue将不会在构建存在如果DEBUG没有定义,与第二示例中,调用SetPrivateValue如果将不会在构建存在DEBUG没有被定义.

随着第一个例子,你必须任何电话换到SetPrivateValue#if DEBUG为好.

对于第二个示例,SetPrivateValue将忽略调用,但请注意,它们SetPrivateValue本身仍将被编译.如果您正在构建库,这很有用,因此引用库的应用程序仍然可以使用您的函数(如果满足条件).

如果要省略调用并保存被调用者的空间,可以使用以下两种技术的组合:

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
    #if DEBUG
    // method body here
    #endif
}
Run Code Online (Sandbox Code Playgroud)


Ken*_*nky 5

让我们假设您的代码也有一个#else定义空存根函数的语句,解决了 Jon Skeet 的观点之一。两者之间还有第二个重要区别。

假设#if DEBUGorConditional函数存在于您的主项目可执行文件所引用的 DLL 中。使用#if,将根据库的编译设置执行条件评估。使用该Conditional属性,将根据调用程序的编译设置执行条件的评估。