0

0

c# LazyInitializer 的用法 c#线程安全的延迟初始化

畫卷琴夢

畫卷琴夢

发布时间:2026-01-19 11:47:02

|

370人浏览过

|

来源于php中文网

原创

lazyinitializer.ensureinitialized 更轻量,因其不创建 lazy 对象,直接在字段上原子赋值,避免状态机、委托封装及同步开销;适用于简单延迟初始化场景,但需注意异常缓存与闭包变量线程安全。

c# lazyinitializer 的用法 c#线程安全的延迟初始化

LazyInitializer.EnsureInitialized 为什么比 new Lazy() 更轻量

LazyInitializer.EnsureInitialized 不创建额外对象,直接在字段上做原子赋值;而 Lazy<t></t> 是一个完整类,带状态机、委托封装和线程同步开销。当只需“首次调用时初始化一次”,且初始化逻辑简单(比如 new 一个对象),EnsureInitialized 更合适。

典型适用场景:静态只读字段、实例字段的延迟构造,尤其在高频访问但初始化成本高、又不希望引入 Lazy<t></t> 对象分配的场合。

  • 必须配合 ref 参数使用,目标字段类型为 T(不是 Lazy<t></t>
  • 初始化委托 Func<t></t> 只会在第一次调用时执行,后续返回已存值
  • 内部用 Interlocked.CompareExchange 保证线程安全,无锁路径下性能接近普通字段读取

如何正确使用 EnsureInitialized 避免重复初始化或空引用

常见错误是把未初始化的字段传入后,又在外部判空再调用 —— 这会破坏原子性,导致多次初始化或竞态。正确做法是始终通过 EnsureInitialized 访问,不单独判空。

例如,以下写法危险:

酷表ChatExcel
酷表ChatExcel

北大团队开发的通过聊天来操作Excel表格的AI工具

下载
if (_instance == null) // ❌ 竞态窗口:可能多个线程同时进入
{
    _instance = CreateInstance();
}

应统一走 EnsureInitialized

private static SomeService _instance;
private static readonly object _lock = new object();

public static SomeService Instance
{
    get => LazyInitializer.EnsureInitialized(ref _instance, () => new SomeService());
}
  • 字段 _instance 声明为 SomeService,不是 Lazy<someservice></someservice>
  • 初始化委托必须是纯函数(无副作用),否则重复执行会出问题(虽然实际不会重复,但逻辑上不能假设只跑一次)
  • 如果初始化可能抛异常,异常会被缓存并每次重抛 —— 这点和 Lazy<t></t>IsValueCreated 行为一致

EnsureInitialized 和 Lazy 在异常处理上的关键差异

两者都会缓存首次初始化时抛出的异常,并在后续访问时原样重抛。但 LazyInitializer 没有暴露类似 Lazy<t>.IsValueCreated</t>Lazy<t>.Value</t> 的状态查询机制,也无法区分“尚未初始化”和“初始化失败”。这意味着:一旦初始化委托抛异常,该字段将永远处于“失败态”,后续所有访问都直接抛同一异常。

  • 无法重试:没有 Retry 或重置方法,只能靠外部重建字段(如用 volatile + 手动锁)
  • 调试困难:异常堆指向 EnsureInitialized 内部,需检查委托内代码
  • 若需容错或重试逻辑,应改用 Lazy<t></t> 并捕获其 Value getter 异常,或自行封装带重试的初始化逻辑

多参数初始化或依赖注入场景下怎么写

LazyInitializer.EnsureInitialized 只接受无参 Func<t></t>,不支持直接传参。若初始化需要外部依赖(如 IOptions<myconfig></myconfig>),必须提前捕获闭包变量。

private static MyProcessor _processor;
private static IOptions<MyConfig> _config;

public static void Initialize(IOptions<MyConfig> config) => _config = config;

public static MyProcessor Processor => 
    LazyInitializer.EnsureInitialized(ref _processor, () => new MyProcessor(_config.Value));
  • 闭包变量(如 _config)必须在线程安全前提下被设置,否则可能捕获到 null 或旧值
  • 避免在 lambda 中调用虚方法或可能被重写的成员,因初始化时机不确定,对象状态可能未就绪
  • 若依赖项本身也是延迟初始化的,需确保其初始化顺序 —— EnsureInitialized 不提供依赖拓扑管理能力
实际用的时候,最容易被忽略的是异常缓存行为和闭包变量的生命周期管理。这两个点不注意,线上可能表现为“服务启动后首次调用必失败,之后一直失败”,而不是预期的“失败后下次重试成功”。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

252

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1049

2024.03.01

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

75

2025.10.23

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

214

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

192

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

61

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

434

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

601

2023.08.10

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

23

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号