Effective C# (Covers C# 6.0), (includes Content Update Program): 50 Specific Ways to Improve Your C#, 3rd Edition By Bill Wagner 讀後心得
類別中物件的初始化有兩種方式:欄位宣告時初始化(Initializers)與建構子(Constructors)初始化。使用欄位宣告時初始化可以確保當存在不只一種建構子時,都能夠確實初始化物件;但在某些情況下有仍其限制。
欄位宣告初始化:
public class MyClass
{
// Initializers will execute in declaring sequences.
// Declare the collection, and initialize it.
private List<string> _labels = new List<string>( );
// Execute after _labels was initialized.
private List<string> _buttons = new List<string>( );
}
Note:即便沒有自定義建構子,Initializers 會被加入到編譯器自動產生的預設建構子;確保執行。
1. 欲宣告物件為 null 或 0 時不需明確宣告初始化。
public struct MyValType
{
// elided
}
public class MyRefType
{
// elided
}
public class Client
{
MyValType _myVal1; // a. initialed to 0
MyValType _myVal2 = new MyValType( ); // b. also 0
MyRefType _myRef1; // c. initialed to null
MyRefType _myRef2 = null; // d. also null
}
a. 利用 cpu instruction 將記憶體配置為 0。
b. 利用 IL instruction initobj 初始化為 0。
c. 利用 cpu instruction 將記憶體配置為 0(null)。
d. 利用 IL instruction initobj 初始化為 0(null)。
a 與 c 效率皆比 b 和 d 好,宣告欄位變數時;並不需要特地設定為 0(null)。
2. 不同建構子有不同的變數初始化方式時,不適合使用 Initialzers 初始化。
public class MyClass2
{
// Becomes garbage after MyClass ( int size ) has executed.
private List<string> _labels = new List<string>( );
public MyClass2( )
{
}
public MyClass2( int size )
{
_labels = new List<string>( size );
}
}
當外部輸入了 List 的 size 當作建構子參數,原先透過 Initializers 初始化的 _labels 馬上就成為用不到的垃圾,此舉造成了系統無效的操作。
3. 想要在捕捉物件初始化的例外狀況時,應將其放置在建構子執行。
public class MyClass2
{
// Cannot catch exception through initializers.
private List<string> _labels = new List<string>( );
public MyClass2( int size )
{
try
{
_labels = new List<string>( size );
}
catch ( Exception e )
{
// Do something
}
}
}
結論:
1. Initializers 確保了類別成員的共同初始化邏輯一定會執行,也減少不同建構子間重覆的程式碼。
2. 小心設計不同建構子間的初始化邏輯,若有複雜的初始化邏輯;考慮使用建構子鏈。
1. Initializers 確保了類別成員的共同初始化邏輯一定會執行,也減少不同建構子間重覆的程式碼。
2. 小心設計不同建構子間的初始化邏輯,若有複雜的初始化邏輯;考慮使用建構子鏈。