(譯注:根據我個人對文章的理解,我把initializer譯為:初始化器,它是 指初始化語法,也就是在一個類裡聲明變量的同時,直接創建實例值的方法。
例:object m_o = new object();如果這段代碼不在任何函數內,但在 一個類裡,它就是一個初始化器,而不管你是把它放在類的開始還以結尾。)
一些類經常不只一個構造函數。時間一長,就難得讓它的成員變量以及 構造函數進行同步了。最好的確保這樣的事不會發生的方法就是:在聲明就是的 時間就直接初始化,而不是在每個構造函數內進行賦值。而且你應該使用初始化 器語法同時為靜態的和實例的變量進行初始化。
在C#裡,當你聲明一個 變量時就自然的構造了這個成員變量。直接賦值:
public class MyClass
{
// declare the collection, and initialize it.
private ArrayList _coll = new ArrayList( );
}
忽 略你最終會給MyClass添加多少個構造函數,_coll會正確的初始化。編譯器會產 生一些代碼,使得在你的任何一個構造函數調用前,都會初始化你聲明的實例變 量。當你添加一個新的構造函數時,_coll就給你初始化了。當你添加了一個新 的變量,你不用在所有的構造函數裡添加初始化代碼;直接在聲明的地方對它進 行初始化就行了。同樣重要的是:如果你沒有明確的聲明任何一個構造函數,編 譯會默認的給你添加一個,並且把所有的變量初始化過程都添加到這個構造函數 裡。
初始化器更像是一個到構造函數的方便的快捷方法。初始化生成的 代碼會放置在類型的構造函數之前。初始化會在執行類型的基類的構造函數之前 被執行,並且它們是按你聲明的先後關系順序執行的。
使用初始化器是 一個最簡單的方法,在你的類型裡來避免使用一些沒有賦值的變量,但這並不是 很好。下面三種情況下,你不應該使用初始化器語法。首先就是,如果你是初始 化一個對象為0,或者為null。系統默認會在你任何代碼執行前,為所有的內容 都初始化為0。系統置0的初始化是基於底層的CPU指令,對整個內存塊設置。你 的任何其它置0的初始化語句是多余的。C#編譯器忠實的添加額外的指令把內存 設置為0。這並沒有錯,只是效率不高。事實上,如果是處理值類型數據,這是 很不值的:
MyValType _MyVal1; // initialized to 0
MyValType _MyVal2 = new MyValType(); // also 0
兩條語句 都是把變量置為0。第一個是通過設置包含_MyVal1的內存來置0;而第二個是通過 IL指令initobj,這對變量_MyVal2會產生裝箱與拆箱操作。這很要花一點額外的 時間(參見原則17)。
第二個低效率的是在你為一個對象添加兩個構造函 數時會產生。你使用初始化器初始化變量,而所有的構造函數也對這些變量進行 了初始化。這個版本的MyClass兩個不同的ArrayList對象在它的構造函數內:
public class MyClass
{
// declare the collection, and initialize it.
private ArrayList _coll = new ArrayList( );
MyClass( )
{
}
MyClass( int size )
{
_coll = new ArrayList( size );
}
}
當你創建一個新的MyClass對象時,特別指定集合的大小,你 創建了兩個數組列表。其中一個很快成為垃圾對象。初始化器在所有的構造函數 之前會執行,構造函數會創建第2個數組列表。編譯器產生了這個的一個版本, 當然這是你決不會手動寫出來的。(參見原則14來使用一個恰當的方法來解決這 個問題)
public class MyClass
{
// declare the collection, and initialize it.
private ArrayList _coll;
MyClass( )
{
_coll = new ArrayList( );
}
MyClass( int size )
{
_coll = new ArrayList( );
_coll = new ArrayList( size );
}
}
最後 一個原因要把初始化放到構造函數裡就是促使異常的捕獲。你不能在初始化器中 使用try塊,任何在構造時因成員變量產生的異常可能衍生到對象的外面。你無 法試圖在你的類裡來捕獲它。你應該把那些初始化代碼移到構造函數裡,這樣你 就可以捕獲異常從而保證你的代碼很友好(參見原則45)。
變量初始化器 是一個最簡單的方法,在忽略構造函數時來保證成員變量被正確的初始化。初始 化器在所有的構造函數之前被執行。使用這樣的語法意味著當你在為後來發布的 版本中添加了構造函數時,不會忘記添加恰當的初始化到構造函數裡。當構造函 數與初始化生成同樣的成員對象時,就使用初始化器。閱讀簡單而且易於維護。
返回教程目錄