【问题标题】:Can I decorate a method in C# such that it is compiled only in debug versions?我可以在 C# 中装饰一个方法,使其仅在调试版本中编译吗?
【发布时间】:2023-04-11 06:05:01
【问题描述】:

我知道您可以在 C# 中使用 #if DEBUG 等,但是否可以创建完全忽略的方法或类,包括所有的用法包裹在#if DEBUG 块内?

类似:

[DebugOnlyAttribute]
public void PushDebugInfo()
{
    // do something
    Console.WriteLine("world");
}

然后:

void Main()
{
    Console.WriteLine("hello ");
    Xxx.PushDebugInfo();
}

如果定义了DEBUG,它将打印“hello world”,否则只打印“hello”。但更重要的是,MSIL 根本不应该在发布版本中包含方法调用。

我相信我所追求的行为类似于 Debug.WriteLine,它的调用被完全删除,并且对发布版本的性能或堆栈深度没有影响。

并且,如果可能在 C# 中,任何使用此方法的 .NET 语言的行为是否相同(即编译时与运行时优化)。

还标记了,因为基本上我在那里需要这个方法。

【问题讨论】:

标签: f# c# .net f# debug-build


【解决方案1】:

您似乎在寻找ConditionalAttribute

例如,这是Debug class source code的一部分:

static partial class Debug
{
    private static readonly object s_ForLock = new Object();

    [System.Diagnostics.Conditional("DEBUG")]
    public static void Assert(bool condition)
    {
        Assert(condition, string.Empty, string.Empty);
    }

    [System.Diagnostics.Conditional("DEBUG")]
    public static void Assert(bool condition, string message)
    {
        Assert(condition, message, string.Empty);
    }
 ................................

【讨论】:

  • 这些方法是在任何版本中编译并被 JIT 删除,还是如 MSDN 所说,被编译器删除(这需要两个构建供其他人使用,取决于他们的调试设置)?
  • @Abel 这是一个编译细节。 JIT 与此无关。顺便说一句,构建配置很容易配置,不是吗?
  • 是的,他们是。无论如何,它给了我足够的弹药继续前进。它有这种“aha-erlebnis”的感觉,我想我几年前用过或见过,但忘了它;)。
  • @Abel .NET 生态系统足够大,从长远来看会忘记细节:D
【解决方案2】:

您可以使用[Conditional("DEBUG")] 装饰您的方法,使其仅在调试模式下执行,而不会在发布模式下执行。

您可以在MSDN 上阅读更多关于 Conditional 属性的信息:

Conditional 属性通常与DEBUG 标识符一起使用,以启用调试版本的跟踪和日志记录功能,但不在发布版本中

【讨论】:

  • 好像是我要找的东西。如果我有var x = Xxx.SomeDebugOnlyMethod(),会发生什么?编译时错误?您是否知道是否存在不需要两次构建但可以通过 JIT 优化的类似内容?
  • @Abel 你说的SomeDebugOnlyMethod() 是什么意思,没明白你的意思
  • 在发布模式下不会执行下一个引用x的代码
  • 是的。不,对不起。我的意思是:我将值分配给一个变量。如果rh端没有编译,应该会变成编译错误吧?
  • 刚刚找到:“条件方法必须是类或结构声明中的方法,并且返回类型必须为 void。”,来自 MSDN。
【解决方案3】:

我已经看到在某些地方使用了以下方法,尽管它可能不是最好的方法。

public static class Debug
{
    public static bool IsInDebugMode { get; set; }

    public static void Print(string message)
    {
        if (IsInDebugMode) Console.Write(message);
    }
}

然后,您可以在 main 方法中的某处设置 IsInDebugMode 布尔值,然后全部执行 Debug.Print("yolo") 调用。

编辑:这当然可以通过额外的格式化输出包装器、自动换行符等进行扩展。

【讨论】:

  • 不,这确实不是我想要的,因为它仍然会执行该方法。我试图阻止这种情况。在紧密的循环中,这会对性能产生不利影响。
  • 我只在 Java 中将它用于小型家庭项目,它是一种快速启动和运行调试打印的方法,但是是的,如果性能至关重要(这意味着它已被证明/证明有必要进行优化)这可能不是最优的(尽管布尔检查真的很便宜,所以无论如何你都可以侥幸逃脱)。我从未使用过ConditionalAttribute,但它看起来很有希望,所以它可能更适合你。
  • @freedomn-m,在大多数情况下就足够了,这就是我们使用日志记录和日志设置的方式。但是在某些情况下,我需要在紧密的循环中收集信息,在这种情况下,最好根本不进行方法调用。当然,还有一种情况是您只想在调试版本中包含安全敏感信息。
  • 我个人更喜欢这种方法,因为这意味着您可以在生产环境中打开调试,而无需重新编译。但是,在某些情况下(比如这个问题)它的开销太高了。
猜你喜欢
  • 2017-10-15
  • 2023-03-17
  • 2018-08-10
  • 1970-01-01
  • 2022-01-19
  • 2012-12-15
  • 2022-01-04
  • 1970-01-01
  • 2021-08-25
相关资源
最近更新 更多