调试日志弄乱了我的代码

时间:2014-03-13 13:18:38

标签: c# windows debugging

我正在尝试将调试日志添加到我的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

5 个答案:

答案 0 :(得分:6)

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

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

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

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

这样做的另一个好处是不会使堆栈跟踪混乱,而不是移动方法中的#if

答案 1 :(得分:2)

很晚才回答,但我留待将来参考。在我看来,你应该考虑面向方面编程来完成这样的任务。也就是说,如果您不需要为小任务添加此类复杂性,则可以将预处理器条件移至日志方法中:

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

不要担心留空方法,JIT会对其进行优化,甚至不会被调用。它几乎等同于:

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

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

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());

你会得到:

Calling SomeCode1
SomeCode1 completed
Calling SomeCode2
SomeCode2 completed
Calling SomeCode3
SomeCode3 completed

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

答案 2 :(得分:0)

您可以将预处理程序指令移动到debuglogger函数,也可以使用可配置的日志记录框架,该框架允许您配置何时记录而不是在构建时依赖预处理程序语句。那样你就可以开启&#34;无需重建应用程序即可进行日志记录。

答案 3 :(得分:0)

您可以使用AOP,但我自己没有尝试过。

或者,您可以采取一些措施来帮助提高代码的可读性,例如使用Conditional attribute

使用debuglogger属性标记Conditional方法,无需#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方法记录&#34; SomeCodeN已完成&#34;消息,进一步简化了代码

debuglogger("The functionstarted");
someCode1(); 
someCode2(); 
someCode3();
debuglogger("Function End");

public void someCode1()
{
    // Do something
    debuglogger("someCode1 Finished");
}

答案 4 :(得分:0)

马克·格拉维尔最近发表了一个利用偏分类的有趣想法。 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");
    }
}

调试/跟踪逻辑与正常代码分离,在更改构建选项时,它不会被编译。