请说明在 C# 中单例模式有哪些实现方式,并谈谈它们各自的适用场景和注意事项。
考察说明
考察对单例模式多种实现方式的理解及线程安全等细节。
回答思路
- 【回答框架 1】单例模式确保一个类只有一个实例,并提供一个全局访问点。C# 中常见实现有:非线程安全版、加锁版、静态初始化版、Lazy<T> 版。
- 【回答框架 2】非线程安全版在多线程下可能产生多个实例,不推荐在生产环境使用。加锁版通过 lock 保证线程安全,但每次访问都有性能开销。
- 【回答框架 3】静态初始化版利用 CLR 的静态字段初始化机制,由 CLR 保证只执行一次,是线程安全且简洁的方式,但无法控制初始化时机。
- 【回答框架 4】Lazy<T> 版结合了懒加载和线程安全,默认使用 ExecutionAndPublication 模式,代码简洁且性能好,推荐使用。
- 【回答框架 5】更多高级考虑包括:防止反射和序列化破坏单例,可在构造函数中抛出异常或实现 IDeserializationCallback。
- 【关键点 1】静态初始化版和 Lazy<T> 版是推荐的线程安全实现。
- 【关键点 2】加锁版虽通用,但可用静态初始化或 Lazy<T> 替代以减少开销。
- 【关键点 3】反射可能破坏单例,需要额外防护。
- 【易错点 1】非线程安全版在多线程下有竞态条件。
- 【易错点 2】懒加载与饿汉式初始化时机不同,需按需求选择。
- 【易错点 3】未处理序列化时,反序列化可产生新实例。