我最近浏览了一些代码,并考虑是否需要谨慎处理Debug.Assert
语句中的表达式,例如昂贵的操作或带有副作用的表达式。但是,看起来编译器在完全删除Assert
语句和内部表达式方面非常聪明。
例如,以下内容仅在调试版本上打印:
static void Main(string[] args)
{
Debug.Assert(SideEffect());
}
private static bool SideEffect()
{
Console.WriteLine("Side effect!");
return true;
}
这会抱怨在发布版本初始化之前正在使用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;
}
它甚至可以表达这样的表达(在两种情况下都打印“After”):
static void Main(string[] args)
{
if (false) Debug.Assert(true);
Console.WriteLine("After");
}
我对编译器的智能程度以及在Debug.Assert
被删除时正确检测案例的能力感到有些惊讶。所以,它让我好奇..
if
语句。System.Diagnostics.Debug
类是特殊的,还是可以用类似的处理方法构建自己的方法?答案 0 :(得分:23)
Debug.Assert
声明为ConditionalAttribute
;正如文档所述,除非定义了指定的条件编译符号,否则编译器应该忽略方法调用或属性。"
C#编译器对该属性具有特定支持,并在发布版本期间删除Debug.Assert,因此它永远不会是构建表达式树的一部分。
如果您右键单击其中一个Debug.Assert
语句,则应该可以转到该定义。 Visual Studio将向您显示"代码"从元数据生成,您可以看到应用了[Conditional("DEBUG")]
属性。因此,只有当DEBUG
#define
作为您构建的一部分时,才会尊重此代码。
答案 1 :(得分:5)
调试器上的方法使用伪自定义属性ConditionalAttribute
,编译器检测并删除对具有该属性的任何方法的任何调用,除非指定的编译符号(在本例中为DEBUG
) 被定义为。任何人都可以使用void
方法中的属性而不使用任何out
参数。
答案 2 :(得分:4)
我不相信Debug.Assert在任何方面都是特殊的;它只是使用Conditional
属性,以便编译器在检测到“预处理器”定义不存在时将其删除(C#没有预处理器!)。
您可以像这样使用它来做同样的事情(只要您定义了DEBUG
(或者您想要打开的任何符号,TRACE
是另一个受欢迎的符号):
[Conditional("DEBUG"), Conditional("TRACE")]
public void DebugOnlyMethod() {
Console.WriteLine("Won't see me unless DEBUG or TRACE is defined");
}