我想在我的 C# 应用程序中添加日志记录或跟踪,但如果日志详细级别设置得太低以至于消息不会被记录,我不希望记录格式化字符串或计算值的开销。
在 C++ 中,您可以使用预处理器来定义将阻止代码执行的宏,如下所示:
#define VLOG(level,expr) if (level >= g_log.verbosity) { g_log.output << expr; }
这样使用:
VLOG(5,"Expensive function call returns " << ExpensiveFunctionCall());
在 C# 中如何做到这一点?
我已经阅读了解释跟踪和调试工具的 Microsoft 文档 here ,他们声称使用#undef DEBUG 和#undef TRACE 从生成的可执行文件中删除了所有跟踪和调试代码,但它真的删除了整个调用吗?意思是,如果我写
System.Diagnostics.Trace.WriteLineIf(g_log.verbosity>=5,ExpensiveFunctionCall());
如果我取消定义 TRACE,它不会调用我昂贵的函数吗?还是调用电话,然后决定不跟踪任何东西?
无论如何,即使它确实删除了它,这也不如 C++ 宏,因为我不能让那个丑陋的大调用看起来像我在 C++ 中的简单 VLOG() 调用,并且仍然避免评估参数,可以吗?我也不能像在 C++ 中那样通过在运行时定义较低的冗长来避免开销,对吗?
最佳答案
要回答您的一个问题,如果 Trace.WriteLine 被编译出来,则所有必须评估才能调用 Trace.WriteLine(或其 sibling /表亲)的方法调用都不会被调用。因此,继续将昂贵的方法调用作为参数直接放入 Trace 调用中,如果您没有定义 TRACE 符号,它将在编译时被删除。
现在回答有关在运行时更改冗长程度的其他问题。这里的技巧是 Trace.WriteLine 和类似的方法将“params object[] args”作为它们的字符串格式化参数。只有当字符串实际发出时(当详细程度设置得足够高时),该方法才会对这些对象调用 ToString 以从中获取字符串。所以我经常玩的一个技巧是将对象而不是完全组装的字符串传递给这些方法,并将字符串创建留在我传递的对象的 ToString 中。这样运行时性能税只在日志记录实际发生时支付,它让您可以自由更改冗长程度,而无需重新编译您的应用。
关于C# 条件日志记录/跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/555581/