這一切在 Debug模式下工作的很正常,但在release下卻輸出的為空行。release模式很樂 意給你輸出一個空行,然而這並不是你所期望的。傻眼了吧,但編譯器幫不了你 什麼。你的條件編譯塊裡的基礎代碼確實是這樣邏輯。一些零散的#if/#endif塊 使你的代碼在不同的編譯條件下很難得診斷(diagnose)。
C#有更好的選 擇:這就是條件屬性。用條件屬性,你可以在指定的編譯環境下廢棄一個類的部 份函數, 而這個環境可是某個變量是否被定義,或者是某個變量具有明確的值 。這一功能最常見的用法就是使你的代碼具有調試時可用的聲明。.Net框架庫已 經為你提供了了基本泛型功能。這個例子告訴你如何使用.Net框架庫裡的兼容性 的調試功能,也告訴你條件屬性是如何工作的以及你在何時應該添加它:
當你建立了一個Person的對象時,你添加了一個方法來驗證對象的不變 數據(invariants):
private void CheckState( )
{
// Grab the name of the calling routine:
string methodName =
new StackTrace( ).GetFrame( 1 ).GetMethod( ).Name;
Trace.WriteLine( "Entering CheckState for Person:" );
Trace.Write( "\tcalled by " );
Trace.WriteLine( methodName );
Debug.Assert( _lastName != null,
methodName,
"Last Name cannot be null" );
Debug.Assert( _lastName.Length > 0,
methodName,
"Last Name cannot be blank" );
Debug.Assert( _firstName != null,
methodName,
"First Name cannot be null" );
Debug.Assert( _firstName.Length > 0,
methodName,
"First Name cannot be blank" );
Trace.WriteLine( "Exiting CheckState for Person" );
}
這這個方法上,你可能不必用到太多的 庫函數,讓我簡化一下。這個StackTrace 類通過反射取得了調用方法的的名字 。這樣的代價是昂貴的,但它確實很好的簡化了工作,例如生成程序流程的信息 。這裡,斷定了CheckState所調用的方法的名字。被判定(determining)的方法 是System.Diagnostics.Debug類的一部份,或者是System.Diagnostics.Trace類 的一部份。Degbug.Assert方法用來測試條件是否滿足,並在條件為false時會終 止應用程序。剩下的參數定義了在斷言失敗後要打印的消息。Trace.WriteLine 輸出診斷消息到調試控制台。因此,這個方法會在Person對象不合法時輸出消息 到調試控制台,並終止應用程序。你可以把它做為一個先決條件或者後繼條件, 在所有的公共方法或者屬性上調用這個方法。
public string LastName
{
get
{
CheckState( );
return _lastName;
}
set
{
CheckState( );
_lastName = value;
CheckState( );
}
}
在某人試圖給LastName賦空值或者null時,CheckState會在 第一時間引發一個斷言。然後你就可以修正你的屬性設置器,來為LastName的參 數做驗證。這就是你想要的。
但這樣的額外檢測存在於每次的例行任務 裡。你希望只在調試版中才做額外的驗證。這時候條件屬性就應運而生了:
[ Conditional( "DEBUG" ) ]
private void CheckState( )
{
// same code as above
}