【问题标题】:Debug Log mess up my code调试日志弄乱了我的代码
【发布时间】:2015-02-04 19:08:29
【问题描述】:

我正在尝试将调试日志添加到我的 C#.net 代码中。 但它弄乱了我的代码,看起来像地狱。 有什么东西可以自动记录每个代码及其值吗? 现在看起来像这样

    #if DEBUG 
        debuglogger("The functionstarted");
    #endif
    someCode1(); 
    #if DEBUG 
        debuglogger("SomeCode1 Finished");
    #endif
    someCode2(); 
    #if DEBUG 
        debuglogger("SomeCode2 Finished");
    #endif
    someCode3(); 
    #if DEBUG 
        debuglogger("SomeCode3 Finished");
    #endif
    #if DEBUG 
        debuglogger("Function End");
    #endif

【问题讨论】:

  • #if DEBUG 放在 debugLogger 函数中怎么样?
  • 您可以创建一个函数 debugLoggerPrint 来打印字符串,然后您只需要在该函数中使用一次 #if DEBUG 并从您的代码中正常调用它。
  • 或者是时候看看面向方面的编程了...
  • 是的,如果您想完全从主代码中提取日志记录逻辑,PostSharp 之类的东西可能会有所帮助。
  • @Baldrick 该方法仍然会使您的堆栈混乱,最好使用ConditionalAttribute

标签: c# windows debugging


【解决方案1】:

您应该使用ConditionalAttribute。它允许您定义条件不匹配时将在构建时删除的方法:

[Conditional("DEBUG")]
void DebugLog(string message)
{
    // Do some logging...
}

在未定义 DEBUG 的构建中将删除对该方法的调用。就像

#if DEBUG
DebugLog("Testing...");
#endif

与将#if 方法中移动相比,这样做的另一个好处是不会弄乱堆栈跟踪。

【讨论】:

    【解决方案2】:

    很晚的答案,但我留作将来参考。在我看来,对于这样的任务,您应该考虑面向方面编程。也就是说,如果您不需要为小任务增加如此复杂性,您可以将预处理器条件移动到您的 log 方法中:

    public static void Log(string message)
    {
    #if DEBUG
        // Do logging
    #endif
    }
    

    不要担心留下一个空方法,JIT 会优化它,甚至不会被调用。它几乎相当于:

    [Condition("DEBUG")]
    public static void Log(string message)
    

    警告:我说几乎是因为使用带有[Condition] 属性参数的方法甚至不会被评估然后在发布时给出此代码:

    Log(String.Format("Index: {0}", index++));
    

    index 变量永远不会增加,因为 JIT 编译器不会发出对Log 的调用,甚至它的参数也不会被评估。如果您将方法主体保留为空且其中包含 #if 指令,则这是不正确的。不会发出调用(因为主体为空),但会评估其参数。

    此解决方案的问题是它会使您的正常程序流程变得混乱。使用日志调用、参数转储和类似的东西。你能做什么?

    重构你的日志

    如果你多次调用 SomeCode1() 方法,你不应该在每个调用站点登录,更好的是将日志记录移到被调用的方法中。仅在每个函数的开头和结尾记录日志,日志仍会在您的代码中,但会跨越多个函数。

    void SomeCode1() {
        Log("Starting SomeCode1");
        // Do something
        Log("SomeCode1 completed");
    }
    

    然后您的呼叫站点将是干净的:

    SomeCode1();
    SomeCode2();
    SomeCode3();
    

    表达式

    如果性能不是问题(衡量,不要猜测),您可以使用表达式为您解决问题。您也可以记录参数(或字段、对象状态、诊断信息、不变量以及您可能需要的任何其他内容),一切都由诊断开关控制(仅在需要时启用它们)。 LOB 类中没有日志记录代码,但代价是执行速度(和LoggedOperation 函数复杂度)。

    这段代码(对我自己礼貌)非常幼稚,一个体面的实现会复杂得多,所以只需将其视为一个想法而不是实现。

    static void LoggedOperation(Expression<Action> expression)
    {
        MethodCallExpression methodCall = expression.Body as MethodCallExpression;
        if (methodCall != null)
        Log("Calling {0}", methodCall.Method.Name);
    
        expression.Compile()();
    
        if (methodCall != null)
            Log("{0} completed", methodCall.Method.Name);
    }
    

    然后会这样使用:

    LoggedOperation(() => SomeCode1());
    LoggedOperation(() => SomeCode2());
    LoggedOperation(() => SomeCode3());
    

    你会得到:

    调用 SomeCode1 SomeCode1 已完成 调用 SomeCode2 SomeCode2 完成 调用 SomeCode3 SomeCode3 完成

    AOP 将为您提供更简洁的代码,但在许多情况下这可能就足够了。

    【讨论】:

    • 只是一个 nitpik,这些是 Lamba 表达式,而不是 LINQ 表达式。
    • 吹毛求疵,这些是 Lambda 表达式,而不是 Lamba 表达式!
    【解决方案3】:

    您可以将预处理器指令移至debuglogger 函数,或使用可配置的日志框架,让您配置何时记录,而不是在构建时依赖预处理器语句。这样您就可以“打开”日志记录,而无需重新构建应用程序。

    【讨论】:

      【解决方案4】:

      你可以使用AOP,虽然我自己没有尝试过。

      或者,您可以做很多事情来帮助提高代码的可读性,例如使用Conditional attribute

      Conditional 属性标记debuglogger 方法就不需要#if DEBUG 代码

      [Conditional("DEBUG")]
      public void debuglogger(string message)
      {
          // Logging code goes here
      }
      
      debuglogger("The functionstarted");
      someCode1(); 
      debuglogger("SomeCode1 Finished");
      someCode2(); 
      debuglogger("SomeCode2 Finished");
      someCode3();
      debuglogger("SomeCode3 Finished");
      debuglogger("Function End");
      

      我个人也会让someCodeN 方法记录“SomeCodeN Finished”消息,这会进一步简化您的代码

      debuglogger("The functionstarted");
      someCode1(); 
      someCode2(); 
      someCode3();
      debuglogger("Function End");
      
      public void someCode1()
      {
          // Do something
          debuglogger("someCode1 Finished");
      }
      

      【讨论】:

        【解决方案5】:

        Mark Gravell 最近发布了一个利用部分类的有趣想法。 Link to his plog post

        项目结构:

        -Foo.cs
        -Foo.debug.cs
        

        这里是类:

        // Foo.debug.cs
            #if DEBUG
                partial class Foo
                {
                    partial void Trace(string value)
                    {
                        Console.WriteLine("The value is: {0}", value);
                    }
                }
            #endif
        
        // Foo.cs
        partial class Foo
        {
            partial void Trace(string value);
            public void MethodWithTracing()
            {
                Trace("This is traced");
            }
        }
        

        调试/跟踪逻辑与普通代码分离,更改构建选项时不会编译。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-23
          • 1970-01-01
          • 2011-03-12
          • 1970-01-01
          • 2013-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多