Chapter 2 - Item 12 : Prefer Member Initializers to Assignment Statements

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. 小心設計不同建構子間的初始化邏輯,若有複雜的初始化邏輯;考慮使用建構子鏈。