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 最佳实践
相关推荐
大空大地202643 分钟前
流程控制语句--switch多分支语句使用、while循环语句的使用、do...while语句、for循环
c#
苏渡苇2 小时前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
kylezhao20192 小时前
C#序列化与反序列化详细讲解与应用
c#
JQLvopkk2 小时前
C# 实践AI :Visual Studio + VSCode 组合方案
人工智能·c#·visual studio
故事不长丨3 小时前
C#线程同步:lock、Monitor、Mutex原理+用法+实战全解析
开发语言·算法·c#
kingwebo'sZone3 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
短剑重铸之日3 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
大空大地20263 小时前
表达式与运算符
c#
feasibility.4 小时前
AI 编程助手进阶指南:从 Claude Code 到 OpenCode 的工程化经验总结
人工智能·经验分享·设计模式·自动化·agi·skills·opencode
向上的车轮4 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net