C#编译器如何在发布版本中删除Debug.Assert?

Sco*_*ner 24 c# debugging assert

我最近经历了一些代码,并考虑是否需要小心处理Debug.Assert语句中的表达式,例如昂贵的操作或带有副作用的表达式.但是,看起来编译器在完全删除Assert语句和内部表达式方面非常聪明.

例如,以下内容仅在调试版本上打印:

static void Main(string[] args)
{
    Debug.Assert(SideEffect());
}
private static bool SideEffect()
{
    Console.WriteLine("Side effect!");
    return true;
}
Run Code Online (Sandbox Code Playgroud)

这会抱怨o在发布版本初始化之前使用它:

static void Main(string[] args)
{
    object o;
    Debug.Assert(Initialize(out o));
    o.ToString();
}
private static bool Initialize(out object o)
{
    o = new object();
    return true;
}
Run Code Online (Sandbox Code Playgroud)

它甚至可以表达这样的表达(在两种情况下打印"After"):

static void Main(string[] args)
{
    if (false) Debug.Assert(true);
    Console.WriteLine("After");
}
Run Code Online (Sandbox Code Playgroud)

我对编译器的智能程度以及Debug.Assert删除时正确检测案例的能力感到有些惊讶.所以,它让我好奇..

  • 该陈述究竟是如何删除的?必须在删除语句之前构建表达式树,才能正确执行上述if语句.
  • System.Diagnostics.Debug这里的类是特殊的,还是可以用类似的处理来构建自己的方法?
  • 有没有办法在这里"欺骗"预处理器?更好的是,在现实世界的代码中可能会遇到哪些情况可能会出现问题?

And*_*own 23

Debug.Assert声明ConditionalAttribute; 正如文档所述,这"[i]指示编译器应该忽略方法调用或属性,除非定义了指定的条件编译符号."

C#编译器具有对该属性的特定支持,并在发布版本期间删除Debug.Assert,因此它永远不会是构建表达式树的一部分.

如果右键单击其中一个Debug.Assert语句,则应该可以转到该定义.Visual Studio将显示从元数据生成的"代码",您可以在其中看到[Conditional("DEBUG")]应用的属性.所以,当这个代码只推崇DEBUG#define倒是作为构建的一部分.


Mar*_*ade 5

调试器上的方法使用伪自定义属性,ConditionalAttribute编译器检测并删除对具有该属性的任何方法的任何调用,除非定义了指定的编译符号(在本例中DEBUG).任何人都可以使用void没有任何out参数的方法的属性.