確保一個類別只有一個實例,並提供全域存取點。本範例展示最基礎的「懶漢式」實作,並說明其在多執行緒環境下的問題與改進方向。
using System;
class SingletonPage
{
private static SingletonPage _instance;
// 私有建構子,防止外部 new
protected SingletonPage()
{
Console.WriteLine("唯一實例被建立!");
}
// 公開靜態方法取得實例
public static SingletonPage GetInstance()
{
if (_instance == null)
_instance = new SingletonPage();
return _instance;
}
}
// 測試
class TestApp
{
public static void Main()
{
Console.WriteLine("'create' pagea:");
var a = SingletonPage.GetInstance();
Console.WriteLine("'create' pageb:");
var b = SingletonPage.GetInstance();
Console.WriteLine("'create' pagec:");
var c = SingletonPage.GetInstance();
Console.WriteLine("'create' paged:");
var d = SingletonPage.GetInstance();
Console.WriteLine($"所有變數指向同一實例: {ReferenceEquals(a, b) && ReferenceEquals(b, c) && ReferenceEquals(c, d)}");
}
}
'create' pagea:
唯一實例被建立!
'create' pageb:
'create' pagec:
'create' paged:
所有變數指向同一實例: True
上述 if (_instance == null) 檢查與 new SingletonPage() 非原子操作,多執行緒同時進入可能建立多個實例。
class SingletonPage
{
private static SingletonPage _instance;
private static readonly object _lock = new object();
private SingletonPage() { Console.WriteLine("Instance created"); }
public static SingletonPage GetInstance()
{
if (_instance == null) // 第一次檢查,避免每次進鎖
{
lock (_instance) // 鎖定
{
if (_instance == null) // 第二次檢查
_instance = new SingletonPage();
}
}
return _instance;
}
}
using System;
class SingletonPage
{
private SingletonPage() { Console.WriteLine("Instance created"); }
private static readonly Lazy _lazy =
new Lazy(() => new SingletonPage(), true); // true = 執行緒安全
public static SingletonPage Instance => _lazy.Value;
}
Lazy<T> 內建雙重檢查鎖定,程式碼簡潔且效能佳。true 參數啟用發布模式下的執行緒安全。