C#设计模式 单例模式实现方式

在 C# 中实现单例模式有多种方式,以下为 6 种常见的 C# 单例实现方式,并说明它们的优缺点和适用场景。


1. 饿汉式(Eager Initialization)

类加载时就创建实例,线程安全。

csharp 复制代码
public sealed class EagerSingleton
{
    private static readonly EagerSingleton instance = new EagerSingleton();

    // 显式静态构造函数(可选),确保在首次访问前初始化
    static EagerSingleton() { }

    private EagerSingleton() { }

    public static EagerSingleton Instance => instance;
}

✅ 优点:线程安全、简单

❌ 缺点:不能懒加载,可能浪费资源


2. 懒汉式(Lazy, 非线程安全)

首次调用时创建实例,但多线程下不安全(仅用于教学,不推荐生产使用)。

csharp 复制代码
public sealed class LazyUnsafeSingleton
{
    private static LazyUnsafeSingleton instance;

    private LazyUnsafeSingleton() { }

    public static LazyUnsafeSingleton Instance
    {
        get
        {
            if (instance == null)
                instance = new LazyUnsafeSingleton();
            return instance;
        }
    }
}

❌ 不适用于多线程环境


3. 加锁懒汉式(线程安全但性能差)

每次访问都加锁,保证线程安全但效率低。

csharp 复制代码
public sealed class LockedSingleton
{
    private static LockedSingleton instance;
    private static readonly object lockObj = new object();

    private LockedSingleton() { }

    public static LockedSingleton Instance
    {
        get
        {
            lock (lockObj)
            {
                if (instance == null)
                    instance = new LockedSingleton();
                return instance;
            }
        }
    }
}

✅ 线程安全

❌ 每次都加锁,性能开销大


4. 双重检查锁定(Double-Checked Locking)

兼顾懒加载和性能,线程安全。

csharp 复制代码
public sealed class DoubleCheckedSingleton
{
    private static volatile DoubleCheckedSingleton instance;
    private static readonly object lockObj = new object();

    private DoubleCheckedSingleton() { }

    public static DoubleCheckedSingleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (lockObj)
                {
                    if (instance == null)
                        instance = new DoubleCheckedSingleton();
                }
            }
            return instance;
        }
    }
}

✅ 线程安全、懒加载、性能较好

⚠️ 需要 volatile 防止指令重排序(C# 中 volatile 确保内存可见性)


5. 静态内部类(C# 中用嵌套类模拟)

C# 没有 Java 那样的"静态内部类自动懒加载"语义,但可以通过 嵌套私有类 + 静态字段 实现类似效果:

csharp 复制代码
public sealed class NestedSingleton
{
    private NestedSingleton() { }

    public static NestedSingleton Instance => NestedHolder.instance;

    private static class NestedHolder
    {
        internal static readonly NestedSingleton instance = new NestedSingleton();
    }
}

✅ 利用 C# 类型初始化器(Type Initializer)的懒加载和线程安全特性

✅ 推荐使用(简洁、高效、安全)

💡 C# 规范保证:静态字段的初始化在类型首次被使用时由 CLR 自动完成,且是线程安全的。


6. 使用 Lazy<T>(.NET 推荐方式)

.NET 提供了 Lazy<T> 类,天然支持线程安全的懒加载。

csharp 复制代码
public sealed class LazyNetSingleton
{
    private static readonly Lazy<LazyNetSingleton> lazy =
        new Lazy<LazyNetSingleton>(() => new LazyNetSingleton());

    private LazyNetSingleton() { }

    public static LazyNetSingleton Instance => lazy.Value;
}

✅ 最简洁、最安全、最符合 .NET 习惯

✅ 可通过 LazyThreadSafetyMode 控制线程安全级别(默认是完全线程安全)

默认使用 LazyThreadSafetyMode.ExecutionAndPublication,即线程安全。


总结:C# 单例实现推荐排序

方式 懒加载 线程安全 简洁性 推荐度
Lazy<T> ✅ ✅ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
嵌套类(Nested Holder) ✅ ✅ ⭐⭐⭐ ⭐⭐⭐⭐
双重检查锁定 ✅ ✅ ⭐⭐ ⭐⭐⭐
饿汉式 ❌ ✅ ⭐⭐⭐ ⭐⭐
加锁懒汉式 ✅ ✅ ⭐ ⭐
非线程安全懒汉式 ✅ ❌ ⭐⭐ ❌

✅ 最佳实践(推荐写法)

csharp 复制代码
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy = 
        new Lazy<Singleton>(() => new Singleton());

    private Singleton() { }

    public static Singleton Instance => lazy.Value;
}

这个版本:

  • 线程安全
  • 懒加载
  • 代码简洁
  • 符合 .NET 最佳实践
相关推荐
geovindu18 小时前
rust: Composite Pattern
开发语言·后端·设计模式·rust·组合模式
samble19 小时前
从零搭建灌装监控系统(十):生产追溯,条码触发自动记录
c#·wpf·mvvm·modbus·工业控制
YYYing.1 天前
【设计模式系列 (七) 】桥接模式
c++·后端·设计模式·桥接模式
czhc11400756631 天前
退出防呆:用“总闸“收口所有退出入口,以及三个并发语法坑
开发语言·c#
淡海水1 天前
02-01-原理篇-Mark-Sweep与变种算法
算法·unity·c#·游戏引擎·.net·gc
Sirens.1 天前
Java多线程实例:单例模式、阻塞队列、线程池与定时器
java·开发语言·单例模式
UIU1141 天前
同一个变量在两个 .c 文件里类型不一致,程序会怎样?
c++·学习·c#
阿狗童鞋2 天前
设计模式实战指南
设计模式
波力海苔夹心脆6752 天前
C# 值类型与引用类型详解:存储位置、赋值机制、参数传递、相等比较、装箱拆箱与常见陷阱
开发语言·jvm·经验分享·笔记·c#·.net
估值探索者2 天前
【Python量化策略实战 #02】多因子合成mom和vol两因子打分合成
开发语言·c++·python·数据挖掘·c#