2011-04-21 90 views
23

我最近正在浏览一些代码,并考虑是否需要注意Debug.Assert语句中的表达式,例如昂贵的操作或带有副作用的表达式。但是,看起来编译器对于完全删除Assert语句和内部表达式非常聪明。C#编译器如何在发布版本中删除Debug.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; 
} 

它甚至似乎停滞不前直到这样的表达式(在两种情况下打印“之后”):

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

我对编译器在这里的智能以及在Debug.Assert被删除时正确检测病例的能力感到有点惊讶。所以,它让我好奇......

  • 该语句到底是如何删除的?表达式树必须在删除语句之前构建,以正确执行上述if语句。
  • 这里的System.Diagnostics.Debug类是特别的,还是可以用类似的处理来构建你自己的方法?
  • 有什么方法可以在这里“欺骗”预处理器吗?更好的是,在真实世界的代码中可能会遇到哪些情况可能会遇到问题?
+2

请参阅http://blogs.msdn.com/b/ericlippert/archive/2009/09/10/what-s-the-difference-between-conditional-compilation-and-the-conditional-attribute.aspx关于这个问题的一些想法。 – 2011-04-22 05:13:27

回答

22

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

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

如果您右键单击Debug.Assert语句之一,则应该能够转到定义。 Visual Studio会向您显示从元数据生成的“代码”,您可以在其中看到应用的属性[Conditional("DEBUG")]。因此,只有当DEBUG#define'd作为您的构建的一部分时,才会遵守此代码。

5

上的调试器的方法使用伪自定义属性,ConditionalAttribute,该编译器检测并删除与除非指定编译符号该属性的任何方法的任何电话(在此情况下,DEBUG)被定义。任何人都可以在void方法上使用该属性,而不需要任何out参数。

+1

应该强调的是,它会删除未定义匹配符号的调用*** *** - 它可以是任何符号,而不仅仅是DEBUG。另外,“out”参数也被禁止。 – 2011-04-21 22:41:41

+0

MSDN文档声明:“符合公共语言规范(CLS)的编译器允许忽略ConditionalAttribute .C#,J#和Visual Basic编译器支持ConditionalAttribute”。这是否意味着Visual Studio的C#编译器不符合CLS? - 这句话对我来说很神秘。 – Gerard 2013-08-05 07:46:34

+0

不,它只是意味着符合CLS的编译器不必支持ConditionalAttribute,因此它是可选的。 C#符合CLS。 – 2013-08-05 18:24:34

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"); 
} 
+1

我愿意打赌,'Debug'类是当天'ConditionalAttribute'背后的最初动机。 – 2011-04-21 22:43:28

+0

@Matt Greer:最有可能的是,它们似乎是使用它的唯一Framework类。 – 2011-04-21 22:48:13