這個做法在討論靜態成員與靜態建構函式該如何初始化。

首先一個靜態成員是屬於類型而不是屬於某個特定物件(object)(instance), 也就是說只要被宣告為靜態就不能實例化,一般的類型成員實例化後是各自獨立不會互相影響,反而靜態的成員是所有實例都共享這個成員, 因此說一個靜態成員是屬於類型,而不是屬於 instance 自己的。

在下面這個例子中建立了一個靜態屬性 MyStaticProp 與一個屬性 MyProp,我們在 c1 實例中兩個屬性都設定成 2,接著 讀取它們的內容,會發現 MyStaticProp 屬性讀取出來都是一樣的並且可以不用實例化就直接讀取它的值,從這個特性也可以得知 靜態成員是屬於類型的,MyProp 讀取後只有 c1 有修改可以得知一般成員是屬於 instance 自己的。

void Main()
{
	var c1 = new MyClass();
	c1.SetProperty(2);
	Console.WriteLine(c1.GetStaticProperty());
	Console.WriteLine(c1.GetProperty());
	var c2 = new MyClass();
	Console.WriteLine(c2.GetStaticProperty());
	Console.WriteLine(c2.GetProperty());
	Console.WriteLine(MyClass.MyStaticProp);
	// Console.WriteLine(MyClass.MyProp);
}

public class MyClass
{
	public int MyProp { get; set; }
	public static int MyStaticProp { get; set; }

	public int GetStaticProperty() => MyStaticProp;

	public int GetProperty() => MyProp;

	public void SetProperty(int i)
	{
		MyProp = i;
		MyStaticProp = i;
	}
}

從上面提到的特性可以知道一般的建構函式是沒辦法初始化靜態成員的,因為一般的建構函式是只有在創建 instance 才會呼叫。

void Main()
{
	Console.WriteLine(MyClass.MyStaticProp);
}

public class MyClass
{
	public static int MyStaticProp { get; set; }
	
	public MyClass()
	{
		MyStaticProp = 1;
	}
}

所以要初始化靜態成員需要使用靜態建構函式或使用做法 12 提到的 Initializers,同樣也要注意執行的順序以下範例也同樣 Initializers 會先執行之後才是靜態建構函式所以結果會輸出 1。

void Main()
{
	Console.WriteLine(MyClass.MyStaticProp);
}

public class MyClass
{
	public static int MyStaticProp { get; set; } = 2;

	static MyClass()
	{
		MyStaticProp = 1;
	}
}

通常靜態建構函式是最優先執行的,但是在下面這個例子因為是在靜態欄位就直接呼叫實例化因此私有的建構函式才會先執行。

public class Singleton
{
	// Static field initializer calls instance constructor.
	private static Singleton instance = new Singleton();

	private Singleton()
	{
		Console.WriteLine("Executes before static constructor.");
	}

	static Singleton()
	{
		Console.WriteLine("Executes after instance constructor.");
	}

	public static Singleton Instance => instance;
}

靜態建構函式最常見的用途是 Singleton 模式,以下寫法就能建立單例模式。

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    static Singleton() {}

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }
}

Summary

這個做法重新討論的靜態成員的特性還有靜態建構函式的用法,基本上建立單例模式一定會用到靜態這個概念,