代码之家  ›  专栏  ›  技术社区  ›  Lucas B

#如果调试与条件(“调试”)。

  •  397
  • Lucas B  · 技术社区  · 15 年前

    在大型项目中,哪一个更适合使用,以及为什么:

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

    [System.Diagnostics.Conditional("DEBUG")]
    public void SetPrivateValue(int value)
    { ... }
    
    8 回复  |  直到 7 年前
        1
  •  538
  •   Sheridan    8 年前

    这取决于你的目的:

    • #if DEBUG :这里的代码在发布时甚至无法到达IL。
    • [Conditional("DEBUG")] :但是,此代码将到达IL。 电话 除非在编译调用方时设置了调试,否则将省略到方法。

    就我个人而言,根据具体情况,我会同时使用:

    条件(“调试”)示例: 我使用它是为了不必在以后的发布过程中返回并编辑代码,但是在调试过程中,我希望确保没有任何错别字。此函数检查在我的inotifyPropertiesChanged资料中尝试使用属性名时是否正确键入属性名。

    [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
        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.
    }
    

    #如果调试示例: 我在尝试为WCF通信设置不同的绑定时使用此方法。

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

    在第一个示例中,代码都存在,但只有在启用Debug之后才会被忽略。在第二个示例中,const端点设置为“localhost”或“basichttpbinding”,这取决于是否设置了debug。


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

    mylibrary.dll文件

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

    当库以发布模式编译时(即没有调试符号),它将永远调用 B() 从内部 A() 省略,即使调用 () 包含,因为调试是在调用程序集中定义的。

        2
  •  61
  •   Jon Skeet    15 年前

    好吧,值得注意的是,它们根本就不是一回事。

    如果未定义调试符号,则在第一种情况下, SetPrivateValue 它本身不会被称为…而在第二种情况下,它将存在,但是 呼叫者 没有调试符号的编译对象将忽略这些调用。

    如果代码及其所有调用方都在同一程序集中,则此差异为 较少的 重要的是-但这意味着在第一个案例中 需要 #if DEBUG 围绕 打电话 代码也一样。

    个人而言,我建议采用第二种方法——但你需要在头脑中清楚地记住它们之间的区别。

        3
  •  42
  •   Paul Fleming    12 年前

    我相信有很多人会不同意我的观点,但是作为一个建筑工人,我经常听到“但是它在我的机器上工作!”我的观点是,你也不应该使用它。如果您确实需要一些东西来进行测试和调试,请找出一种方法使该可测试性与实际的生产代码分离。

    抽象单元测试中的模拟场景,为要测试的一次性场景制作一次性版本的东西,但不要将调试测试放入为生产版本测试和编写的二进制代码中。这些调试测试只是从开发人员那里隐藏可能的错误,所以直到稍后的过程中才会发现它们。

        4
  •  12
  •   sofsntp    9 年前

    这个也很有用:

    if (Debugger.IsAttached)
    {
    ...
    }
    
        5
  •  9
  •   P Daddy    15 年前

    在第一个例子中, SetPrivateValue 如果 DEBUG 未定义,使用第二个示例, 电话 设置私有值 如果 调试 未定义。

    在第一个示例中,您必须将 设置私有值 具有 #if DEBUG 也。

    在第二个示例中,调用 设置私有值 将被省略,但请注意 设置私有值 它本身仍将被编译。如果您正在构建一个库,这很有用,因此引用您的库的应用程序仍然可以使用您的函数(如果满足条件)。

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

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

    假设你的代码也有一个 #else 定义了一个空存根函数的语句,用于寻址jon skeet的一个点。两者之间还有第二个重要区别。

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

        7
  •  2
  •   Steven J. Hathaway    11 年前

    我有一个SOAP WebService扩展,可以使用自定义的[traceExtension]记录网络流量。我只在调试版本时使用它,在发布版本中省略它。使用if debug包装[traceextension]属性,从而将其从发布版本中移除。

    #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(...)
    
        8
  •  0
  •   Yashwant Shukla    7 年前

    通常,您需要在program.cs中使用它,在该程序中,您要决定对非调试代码运行调试,而在Windows服务中,这一点太多了。所以我创建了一个只读字段isdebugmode,并在静态构造函数中设置它的值,如下所示。

    static class Program
    {
    
        #region Private variable
        static readonly bool IsDebugMode = false;
        #endregion Private variable
    
        #region Constrcutors
        static Program()
        {
     #if DEBUG
            IsDebugMode = true;
     #endif
        }
        #endregion
    
        #region Main
    
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
    
            if (IsDebugMode)
            {
                MyService myService = new MyService(args);
                myService.OnDebug();             
            }
            else
            {
                ServiceBase[] services = new ServiceBase[] { new MyService (args) };
                services.Run(args);
            }
        }
    
        #endregion Main        
    }
    
    推荐文章