首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C# 單例模式深度解析:Instance 屬性、靜態構造函數與線程安全

     編輯:程式設計疑難解答

原始代碼問題

public class Manager {
    private static Manager _instance;
    public static Manager Instance {
        get { return Manager._instance; } // 未初始化,永遠返回 null
    }
    public bool Active { get; set; }
    public bool A() { return true; }
}

直接訪問 Manager.Instance.Active 會拋 NullReferenceException。

標準單例寫法對比

1. 懶漢式 + 雙重檢查鎖 (線程安全、延遲初始化)

public sealed class Manager {
    private static volatile Manager _instance;
    private static readonly object _lock = new object();
    private Manager() {} // 私有構造函數

    public static Manager Instance {
        get {
            if (_instance == null) {
                lock (_lock) {
                    if (_instance == null) _instance = new Manager();
                }
            }
            return _instance;
        }
    }
    public bool Active { get; set; }
    public bool A() => true;
}

2. 靜態構造函數 (CLR 保證線程安全、延遲到首次訪問)


public sealed class Manager {
    private static readonly Manager _instance;
    static Manager() { _instance = new Manager(); } // 靜態構造函數
    private Manager() {}
    public static Manager Instance => _instance;
    public bool Active { get; set; }
    public bool A() => true;
}

3. 嵌套類 (最推薦:簡潔、線程安全、完全延遲)


public sealed class Manager {
    private Manager() {}
    public static Manager Instance => Nested.Instance;
    private class Nested {
        static Nested() {}
        internal static readonly Manager Instance = new Manager();
    }
    public bool Active { get; set; }
    public bool A() => true;
}

為什麼能同時調用屬性與方法?

Manager.Instance 返回的是 同一個對象引用。
Manager.Instance.Active 訪問該對象的屬性。
Manager.Instance.A() 調用該對象的實例方法。
本質都是對同一實例的成員訪問,無任何魔法。

使用示例


Manager.Instance.Active = true;
bool ok = Manager.Instance.A();
Console.WriteLine(Manager.Instance.Active); // True

避坑指南

  • 構造函數必須 private 防止外部 new。
  • 類標記 sealed 防止繼承破壞單例。
  • 不要在屬性 getter 裡做耗時操作(如讀配置、連數據庫),改用 Lazy<T> 或靜態構造函數一次性完成。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved