首页 文章

#if DEBUG vs.条件(“DEBUG”)

提问于
浏览
383

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

#if DEBUG
    public void SetPrivateValue(int value)
    { ... }
#endif

要么

[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }

7 回答

  • 519

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

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

  • 9

    这个也很有用:

    if (Debugger.IsAttached)
    {
    ...
    }
    
  • 10

    这真的取决于你的目标:

    • #if DEBUG :此处的代码在发布时甚至不会达到IL .

    • [Conditional("DEBUG")] :此代码将到达IL,但是除非在编译调用者时设置了DEBUG,否则将省略对该方法的调用 .

    我根据具体情况个人使用:

    Conditional("DEBUG") Example: 我使用这个,所以我不做任何拼写错误 . 当我在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));
    }
    

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

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

    与:

    [Conditional("DEBUG")]
    public void DoSomething() { }
    
    public void Foo()
    {
        DoSomething(); //Code compiles and is cleaner, DoSomething always
                       //exists, however this is only called during DEBUG.
    }
    

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

    #if DEBUG
            public const String ENDPOINT = "Localhost";
    #else
            public const String ENDPOINT = "BasicHttpBinding";
    #endif
    

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


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

    MyLibrary.dll

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

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

  • 59

    嗯,值得注意的是,它们根本不是一回事 .

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

    如果代码及其所有调用者都在同一个程序集中,那么这种差异就不那么重要了 - 但这意味着在第一种情况下,你还需要在调用代码周围使用 #if DEBUG .

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

  • 1

    对于第一个示例,如果未定义 DEBUG ,则构建中将不存在 SetPrivateValue ,如果未定义 DEBUG ,则第二个示例 callsSetPrivateValue 将不存在于构建中 .

    在第一个示例中,您还必须使用 #if DEBUG 包装对 SetPrivateValue 的任何调用 .

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

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

    [System.Diagnostics.Conditional("DEBUG")]
    public void SetPrivateValue(int value){
        #if DEBUG
        // method body here
        #endif
    }
    
  • 4

    让我们假设你的代码也有一个 #else 语句,它定义了一个空存根函数,解决了两个问题之间的第二个重要区别.Jose Skeet 's points. There' .

    假设 #if DEBUGConditional 函数存在于主项目可执行文件引用的DLL中 . 使用 #if ,将对库的编译设置执行条件评估 . 使用 Conditional 属性,将根据调用者的编译设置执行条件评估 .

  • 42

    我有一个SOAP WebService扩展来使用自定义[TraceExtension]记录网络流量 . 我只将它用于Debug构建,并从Release构建中省略 . 使用#if DEBUG包装[TraceExtension]属性,从而将其从Release版本中删除 .

    #if DEBUG
    [TraceExtension]
    #endif
    [System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
    [ more attributes ...]
    public DatabaseResponse[] GetDatabaseResponse( ...) 
    {
        object[] results = this.Invoke("GetDatabaseResponse",new object[] {
              ... parmeters}};
    }
    
    #if DEBUG
    [TraceExtension]
    #endif
    public System.IAsyncResult BeginGetDatabaseResponse(...)
    
    #if DEBUG
    [TraceExtension]
    #endif
    public DatabaseResponse[] EndGetDatabaseResponse(...)
    

相关问题