Lazy是优化启动速度和内存的最简单有效方式,适用于构造成本高、使用概率低、依赖外部资源的成员变量,需用readonly声明并传入Func委托,访问时读.Value属性。

直接用 Lazy
哪些成员变量适合延迟加载
不是所有字段都值得加 Lazy。重点盯住三类:
- 构造成本高:比如需要打开数据库连接、读取大文件、解析复杂 XML/JSON 的对象
- 使用概率低:例如用户仅在“导出报表”功能中才用到的 Excel 生成器,80% 启动后根本不会触发
- 依赖外部资源:如 HTTP 客户端、Redis 连接池、第三方 SDK 实例,它们的初始化可能阻塞主线程或引发超时风险
正确声明 Lazy 成员变量
避免常见错误:别在字段声明时就 new 出实例,也别手动写 if-null-then-new 的逻辑。标准写法如下:
private readonly Lazy<ReportGenerator> _reportGenerator = new(() =>
{
// 这里只在第一次调用 _reportGenerator.Value 时执行
return new ReportGenerator(connectionString, templatePath);
});
关键点:
- 用
readonly保证线程安全和不可变性 - 构造函数传入
Func<t></t>委托,把真正创建逻辑封装进去 - 如果类型有无参构造函数,也可简写为
new Lazy<reportgenerator>()</reportgenerator>,但推荐显式委托,更可控
访问时只需读 .Value 属性
使用时和普通变量几乎一样,只是多一个 .Value:
public void OnExportClick()
{
var generator = _reportGenerator.Value; // 第一次触发初始化
generator.ExportToExcel(data);
}
注意:
- 首次访问
.Value才执行委托,之后每次都是直接返回已创建对象 - 默认线程安全:多个线程同时首次访问,
Lazy<t></t>保证只执行一次初始化 - 异常会被缓存:若初始化抛异常,后续再读
.Value会直接重抛同一异常,不会重试
配合启动流程做分层延迟
光靠单个 Lazy 不够,要结合系统结构分层推进:
- 核心服务(登录、权限)立即初始化
- 二级模块(报表、日志归档、消息推送)全部用
Lazy<t></t>封装 - UI 组件中关联的数据模型,如
Lazy<observablecollection>></observablecollection>,在页面首次显示时才拉取 - 对极少数必须异步加载的,可组合
Task<t></t>+Lazy<task>></task>,实现“首次访问即启动后台加载”


















