我正在尝试将调试日志添加到我的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
答案 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");
}
}
调试/跟踪逻辑与正常代码分离,在更改构建选项时,它不会被编译。