2011-04-21 93 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