C#-静态类和单例模式
目录
静态类是使用类型静态成员做事,单例模式是使用类的对象做事。
静态类只有静态成员,一般工具类都是静态类;静态类不能被实例化、不能实现接口。
单例可以实现接口、支持继承和多态,可以扩展;单例支持继承但需要谨慎涉及,实际项目中单例类通常使用 sealed 防止继承。
静态类的成员在初次使用时由CLR初始化。
定义对比:
// 静态类
public static class MathHelper
{
public static double PI => 3.14;
public static double CircleArea(double r) => PI * r * r;
}
//使用:直接通过类名调用
var area = MathHelper.CircleArea(5);// 单例模式
public sealed class Logger
{
private static readonly Lazy<Logger> _lazy = new(() => new Logger());
public static Logger Instance => _lazy.Value;
// 私有构造函数,防止外部 new
private Logger()
{
}
}
// 使用:通过Instance 获取对象再使用
Logger.Instance.Log("Hello");核心区别一览表
| 维度 | 静态类 | 单例模式 |
|---|---|---|
| 本质 | 不能实例化的类 | 只有一个实例的类 |
| 关键字 | static class | 普通 class + 私有构造函数 |
| 实例 | 没有实例 | 有且仅有一个实例 |
| 构造函数 | 只有静态构造函数 | 私有实例构造函数 |
| 继承 | 不可继承 | 可以(但通常sealed) |
| 实现接口 | 不可以 | 可以 |
| 多态 | 不支持 | 支持 |
| 作为参数传递 | 不可以 | 可以 |
| 依赖注入 | 不友好 | 天然支持 |
| 序列化 | 不可以 | 可以 |
| 单元测试 | 难以 Mock | 通过接口可 Mock |
| 内存释放 | AppDomain 卸载才释放 | 理论可控实际不建议 |
| 线程安全 | 需自行处理 | 需自行处理 |
| 典型用途 | 工具方法/扩展方法 | 全局服务/管理器 |
关键区别:能否"面向对象"
// 单例可以实现接口 -> 可替换,可测试
public interface ILogger
{
void Log(string message);
}
public sealed class FileLogger : ILogger
{
private static readonly Lazy<FileLogger> _lazy = new(() => new FileLogger());
public static FileLogger Instance => _lazy.Value;
private FileLogger()
{
}
public void Log(string message) => File.AppendAllText("log.txt", message);
}
// viewModel 依赖接口,而不是具体类
public class OrderViewModel
{
private readonly ILogger _logger;
// 可以注入真实单例,也可以注入 Mock
public OrderViewModel(ILogger logger)
{
_logger = logger;
}
}
// ===== 静态类无法做到上面这些 =====
public static class StaticLogger
{
public static void Log(string message) => Console.WriteLine(message);
}
public class OrderViewModel
{
public void DoSomething()
{
// 硬依赖,无法替换、无法 Mock
StaticLogger.Log("...");
}
}初始化时机比对
// 静态类
public static class AppConfig
{
// 没有显示静态构造函数 -> CLR 可能提前初始化(beforefieldinit)
public static readonly string Version = LoadVersion();
}
public static class AppConfig2
{
public static readonly string Version = LoadVersion();
// 有显示静态构造函数 -> 精确在首次访问时初始化
static AppConfig2()
{
}
}// 单例 -> 完全可控
// 饿汉式:程序启动即创建
public sealed class EagerSingleton
{
public static readonly EagerSingleton Instance = new();
private EagerSingleton()
{
}
}
// 懒汉式:首次访问时创建(推荐用 Lazy<T>,天然线程安全)
public sealed class LazySingleton
{
private static readonly Lazy<LazySingleton> _lazy = new(() => new LazySingleton());
public static LazySingleton Instance => _lazy.Value;
private LazySingleton() { }
}WPF/MVVM 中的实际场景
// 适合静态类:纯工具方法,无状态
public static class ValueConverterHelper
{
public static Visibility BoolToVisibility(bool value)
=> value ? Visibility.Visible : Visibility.Collapsed;
}
public static class RelayCommandFactory
{
public static RelayCommand Create(Action<object> execute)
=> new RelayCommand(execute);
}// 适合单例:全局服务,有状态,需要通知
public sealed class NavigationService : INotifyPropertyChanged
{
private static readonly Lazy<NavigationService> _lazy = new(() => new());
public static NavigationService Instance => _lazy.Value;
private NavigationService() { }
private object _currentView;
public object CurrentView
{
get => _currentView;
set { _currentView = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// XAML 中可以绑定:
// <ContentControl Content="{Binding CurrentView,
// Source={x:Static local:NavigationService.Instance}}" />现代推荐:依赖注入取代手写单例
// 在 App.xaml.cs 或启动类中
var services = new ServiceCollection();
services.AddSingleton<ILogger, FileLogger>(); // 单例生命周期
services.AddTransient<OrderViewModel>(); // 每次新建
var provider = services.BuildServiceProvider();
var vm = provider.GetRequiredService<OrderViewModel>();依赖注入容器管理的"单例"比手写单例更优:
- 生命周期由容器控制
- 依赖关系清晰
- 天然支持替换和测试
总结
┌─────────────────────────────────────────────────────┐
│ │
│ 静态类 → "一组函数的命名空间",无对象,无多态 │
│ │
│ 单例 → "全局唯一的对象",是对象,有多态 │
│ │
│ 选择标准:需不需要"对象的能力"(接口/继承/传递/注入)│
│ │
│ 不需要 → 静态类 (Math, Path, Convert ...) │
│ 需要 → 单例 (Logger, DbContext, Service ...)│
│ │
└─────────────────────────────────────────────────────┘