在 C# 中将调试字符串保留在生成之外

本文关键字:保留 字符串 调试 | 更新日期: 2023-09-27 18:36:58

编写代码时,我经常在代码中放置调试消息。调试消息由记录器类处理,该类在调试模式下将消息输出到文件,并在发布模式下丢弃它们。

它看起来有点像这样:

class Logger : IDisposable
{
    private StreamWriter m_Logger = null;
    public void Start(string logFile)
    {
        m_Logger = new StreamWriter(logFile);
        m_Logger.AutoFlush = true;
    }
    public void Dispose()
    {
        if (m_Logger != null) m_Logger.Dispose();
    }
    public void WriteLine(string message)
    {
        if (m_Logger != null) m_Logger.WriteLine(message);
    }
}

实例在启动时创建,可从 Program 类访问。然后我像这样检查调试:

#if DEBUG
Program.Log.Start("app.log");
#endif

这很好用,因为它在调试模式下转储调试信息,而不是在发布模式下。但是,如果我通过诸如 strings 之类的实用程序运行发布可执行文件,我仍然可以看到调试字符串。我宁愿将它们完全排除在发布版本之外,以帮助防止逆向工程。

到目前为止,我发现的唯一解决方案是将所有调试消息包装在预处理器条件中:

// < some code here >
#if DEBUG
Program.Log.WriteLine("Some debug message.");
#endif
// < more code here >

这是非常乏味和丑陋的。我的第一个想法是使用某种预处理器宏,但 C# 不支持它们。有没有比我现在使用的解决方案更优雅的解决方案?

在 C# 中将调试字符串保留在生成之外

若要避免在每个 WriteLine 调用中使用 #if-#endif,请尝试在记录器方法本身上使用 ConditionalAttribute:

[Conditional("DEBUG")]
public void WriteLine(string message)
{
    if (m_Logger != null) m_Logger.WriteLine(message);
}

如果是发布版本,这将从 MSIL 中排除。

将 ConditionalAttribute 应用于方法会向编译器指示 对该方法的调用不应编译为Microsoft 中间语言 (MSIL),除非条件编译符号 定义了与条件属性相关联的属性。应用 属性的条件属性指示该属性 不应发出到元数据,除非条件编译 符号已定义

1)将 #ifdef 放在log方法的主体中,这样您就不必在每个日志消息周围放置定义

2)如果您试图防止逆向工程,请混淆代码,这将加密字符串,但这不是故障保护。

3)您可以使用PostSharp之类的东西在事后主动从MSIL中删除代码 http://www.sharpcrafters.com/solutions/logging