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 最佳实践
相关推荐
-银雾鸢尾-15 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-15 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
心平气和量大福大19 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
白露与泡影19 小时前
Arthas 实战指南:从方法耗时定位到 JVM 变量热修改
服务器·jvm·c#
张小姐的猫1 天前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
EIP低代码平台1 天前
EIP低代码平台系统-字典功能讲解
低代码·c#·工作流
吉普赛的歌1 天前
YARP负载均衡配置了多个相同接口导致的报错
c#·yarp
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
张人玉1 天前
C# WinForms——工厂管理系统(C# WinForms)
数据库·sqlite·c#·winform
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范