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 最佳实践
相关推荐
极客智造29 分钟前
深入解析 C# Type 类:解锁反射与动态编程的核心
c#·反射
SmoothSailingT40 分钟前
C#——textBox控件(1)
开发语言·c#
雨中飘荡的记忆1 小时前
观察者模式:从理论到生产实践
java·设计模式
superman超哥1 小时前
仓颉语言中并发集合的实现深度剖析与高性能实践
开发语言·后端·python·c#·仓颉
工程师0071 小时前
C#中的服务注册剖析
c#·服务注册
张人玉2 小时前
c#DataTable类
数据库·c#
缺点内向2 小时前
如何在 C# .NET 中将 Markdown 转换为 PDF 和 Excel:完整指南
pdf·c#·.net·excel
CodeCraft Studio2 小时前
Excel处理控件Aspose.Cells教程:使用C#在Excel中创建旭日图
c#·excel·aspose·excel旭日图·excel库·excel开发控件·excel api库
民乐团扒谱机2 小时前
【微实验】仿AU音频编辑器开发实践:从零构建音频可视化工具
算法·c#·仿真·audio·fft·频谱
阿波罗尼亚2 小时前
Head First设计模式(十二) 设计原则 复合模式
设计模式