自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

dotnethello的博客

微软MVP,持续分享.net编程技术

  • 博客(291)
  • 收藏
  • 关注

原创 CancellationToken 的静默失效:取消令牌最容易踩的坑与正确姿势

取消机制是 .NET 并发里设计最朴素、也最容易被写错的一块。它的错误模式几乎都不是崩溃,而是——令牌传了、代码跑了,但取消永远不生效,或者取消之后留下了半初始化的资源。这篇把链路拆开讲。

2026-11-15 09:13:28 34

原创 HybridCache 上手:Stampede 保护、两级缓存与那些静默失效的选项

自 .NET 9 起,正式转正,成为官方推荐的缓存门面。它不是又一个 IDistributedCache 的包装,而是把内存缓存、分布式缓存、并发去重、序列化、Tag 失效这几件原本要自己拼的事,收进了统一的一套 API。这篇讲清它的核心机制,以及几个典型的静默失效场景。

2026-11-14 09:15:27 165

原创 System.IO.Pipelines:把“只读到半个包“这件事彻底解决

返回了 37 字节,而你等的包头声明有 128 字节。于是你开始写一个byte[]缓冲区、一个offset、一个while循环,外加几处。三天后代码能跑了,但没人敢改。就是微软为这件事给出的标准答案。Kestrel 的请求体、SignalR 的帧、的消息,底层都是它。

2026-11-13 09:11:12 216

原创 partial 不止能拆类:C# 13/14 把 partial 下放到属性、构造函数和事件

这种冲突一般能编过第一遍(增量生成器还没跑),在 CI 或干净构建时才炸,本地"改一点编译一下"的开发节奏里极易漏掉。在 A 项目声明、在 B 项目实现,得到的不是"一个类型的两半",而是两个互不相干的类型——B 里的那份要么缺另一半报错,要么干脆是另一个同名的全新类型。值得注意的是方向:前两次是"让类型能拆",后两次是"让成员的契约能拆"。所以反过来说,想防止误删,给它加个可访问性修饰符就行——这也是 C# 9 之后推荐的做法。摊开——这才让"生成器补实现"从"约定俗成的框架规矩"变成语言层面的契约。

2026-11-12 09:08:50 167

原创 集合表达式不只是语法糖:编译器在替你选构造方式

自定义集合类型想支持,实现(或)并打上即可,构建方法收} // 调用侧:元素直接进 span,没有中间容器 PinyinSet set = [ "ni" , "hao" , "ma" ];typeofPinyinSet} // 调用侧:元素直接进 span,没有中间容器 PinyinSet set = [ "ni" , "hao" , "ma" ];nameof。

2026-11-11 09:11:05 128

原创 TaskCompletionSource 的正确打开方式:RunContinuationsAsynchronously、TrySetXxx 与三个静默坑

(下称 TCS)是把"回调式世界"接入"async/await 世界"的标准桥梁,但它是整个 TPL 里最容易写错的一类 API。错法不抛异常、不报编译警告,只是偶尔在特定线程上死锁,或者让AsyncLocal悄悄断流。这篇把它的完成语义、continuation 执行位置和常见坑一次讲清,代码基于 .NET 10 / C# 14。

2026-11-10 09:20:38 127

原创 在 .NET 里写向量化代码:TensorPrimitives、Vector128/256 与 Vector<T> 该怎么选

尾部长度不足一个向量时用标量兜底,这是手写 SIMD 的标准"主循环 + 尾巴"模式。时部分运算仍可用(JIT 拆成两条 128 位指令模拟),但吞吐掉档且你毫无感知。(假设 256 位 float)做索引运算——在 AVX-512 机器上或 ARM 设备上这个值会变,轻则算错、重则越界。——这些方法内部就是"当前硬件最快的写法",等价于 BCL 帮你维护了一整套手写 SIMD 代码。的设计意图是"宽度就是个实现细节",任何依赖具体值的分支都应该改用显式的。或纯标量路径,别让"看起来向量化了"骗过自己。

2026-11-09 09:16:36 73

原创 await using 不是 using 的异步版:IAsyncDisposable 的释放顺序、异常语义与五个静默坑

而如果它包装的是已完成的结果,第二次又"恰好"正常——bug 于是只在特定路径上偶发。的语义是 finally 里的异常覆盖 try 里的。已 Dispose 的场景下,续体会被投递到一个永远不会被泵送的消息队列,表现为。两者都没有则编译失败。,要么在池化对象上把状态清两次,导致对象被归还两次、进而被两个消费者同时拿到。解决的是"清理不能阻塞线程"的问题,代价是上下文丢失、异常语义更隐蔽、失败,都会把真正的业务异常埋掉,而且堆栈里指向的是清理路径。上,原始结构体的句柄永远不会被释放——典型的静默泄漏。

2026-11-08 09:07:54 171

原创 C# 14 实战三连:field 关键字、extension 成员与 null 条件赋值

NET 10 带来的 C# 14 不是一场 syntax earthquake,但里面藏着三件日常写码频率极高的改进。这篇不讲新闻稿,只讲用起来什么感觉、编译器在背后做了什么、以及哪里会静默踩坑。

2026-11-07 09:21:41 196

原创 DateOnly 与 TimeOnly:把「日期」和「钟面时刻」从 DateTime 里拆干净

用DateTime存生日,你会得到;用DateTime存每天九点开门,你会得到。这两个值都带了一个根本不存在的"时刻",也都没有说清自己属于哪个时区。DateOnly和TimeOnly就是为这类建模错误准备的两个类型——但它们自己的坑,比DateTime更隐蔽,因为错的时候往往不抛异常。

2026-11-06 09:04:54 234

原创 IAsyncEnumerable<T> 的背压是天生的,但你很可能在代码里亲手把它拆掉了

常被当成"异步版 List"来用:定义一个方法,上层消费。看起来只是把换了个返回类型,实际上这两者在内核上是两套东西——一个是,一个是。把前者当后者用,最典型的后果是:内存随数据量线性上涨,而你还在以为自己在"流式处理"。

2026-11-05 09:03:39 57

原创 DI 生命周期静默失效:Captive Dependency、Scope 泄漏与 ValidateOnBuild

依赖注入的坑,几乎都不在于"注册不上",而在于。单例服务里塞进一个DbContext,本地跑一百次都对,上线后偶发;后台服务里直接注入 scoped 服务,进程内存稳步上涨,看着 Gen2 一直涨却找不到根因。。

2026-11-04 09:05:44 172

原创 .NET 可观测性选型:Metrics、ActivitySource、EventSource 到底该用哪个

很多人把Meter当成"新版 EventSource",把当成"新版 DiagnosticSource",然后在生产环境里发现:指标查不到、链路断了、开销还不小。这三个 API 解决的是三个不同维度的问题,混用一定会踩坑。

2026-11-03 09:19:28 173

原创 .NET 的 PriorityQueue:好用,但「优先级」三个字全是坑

NET 6引入的是 BCL 里最容易被低估的集合之一:API 只有几个方法,但它的堆实现、排序语义和线程模型和很多人的直觉都不一样。这篇把容易翻车的地方一次说清。

2026-11-02 09:06:32 176

原创 ref struct 与 scoped:C# 编译器怎么替你守住栈内存

字段、某个属性、或者需要隐式转换的表达式——编译器会先把它拷到一个临时变量,再把这个临时变量按引用传进去。你写的是零拷贝,实际执行的是一次拷贝,没有警告,没有提示。的场合是:你要让调用方传进来的 span 只能在这一个方法里用,从而阻止它被写进字段或返回出去。局部变量,那这次优化多半是负收益。前者常被当成"性能修饰符",后者常被当成"可写可不写的注解"。依然"有效",读出来的是别人刚写进去的数据——无异常、无警告、结果错得很安静。参数的本意是"只读引用,避免拷贝"。编译器不让写,是因为写出来必然是错的。

2026-11-01 09:13:27 226

原创 HttpClient 连接池:SocketsHttpHandler 那些静默生效的默认值

在 .NET 6 之前的语义是"空闲超时后过期",.NET 6 起改为从连接建立时刻计时的绝对寿命——无论忙闲,到期即标记,等当前请求完成后关闭。这个改动让"客户端主动感知 DNS/负载均衡变更"变得可预测:每隔 Lifetime 时间,发往同一主机的新请求会建新连接、重新解析 DNS。QPS 高时,CLOSE_WAIT 状态的 socket 堆积,最终打爆端口。,之后 new 出来的新实例和已挂上的实例毫无关系。这是典型的静默失效:你改了负载均衡策略,客户端没有任何异常,就是"部分流量不听话"。

2026-10-31 09:06:49 207

原创 查表别再用 Dictionary 了?聊聊 FrozenDictionary 和 SearchValues 的正确打开方式

如果你的场景是"构建一次、读取海量次"的查找表,.NET 8 引入的FrozenSet命名空间)就是为它量身定做的;同理,"判断字符/字节是否在某个集合里"这类扫描操作,配合IndexOfAny一族能把循环写成向量化的硬件指令。这篇文章讲清楚它们的机制、什么时候用,以及两个非常典型的静默失效坑。

2026-10-30 09:13:08 63

原创 TimeProvider:把“现在几点“变成一种依赖,而不是一次系统调用

它只是把已有的系统调用换了个可替换的入口。

2026-10-29 20:15:01 157

原创 Native AOT 实战:不是报错,而是静默失效的那些坑

把一个跑得好好的 .NET 项目改用 Native AOT 发布,多数人期待的是"启动更快、内存更省、单文件免装运行时"。。它最伤人的地方不是编译报错——报错你至少会去修——而是运行时静默失效:反射拿到空集合、序列化输出空对象、泛型在用户机器上才炸。

2026-10-28 09:13:02 1588

原创 LINQ 不是语法糖:延迟求值、闭包与装箱的三重成本

至于"既要带状态又不想分配",LINQ 并没有为大多数算子提供带状态参数的公开重载,这条路上只能自己写迭代器或者干脆写循环,别指望编译器替你绕过去。物化本身不坏——它固定了结果、避免了重复枚举——坏的是没有统一的物化边界。如果谓词里打了日志、写了一次数据库、调用了计费接口,这段代码就是错的——不是慢,是错。当方法返回值暴露出去要谨慎:调用方无从知道你交给他的是一个已经算好的数组,还是一段随时会重跑的查询。这在热路径上是实打实的 GC 压力,而且闭包会把捕获的对象一起延长寿命。是协变的,这只对引用类型成立;

2026-10-27 09:03:46 1253

原创 SemaphoreSlim 与限流:从内核信号量到 RateLimiter 的选型与踩坑

信号量是并发控制里最容易被"用错但没报错"的原语。这篇把Semaphore和 .NET 7 起内置的放在一起讲清楚:它们各自适合什么场景,以及哪些写法会让并发约束悄悄失效。

2026-10-26 09:12:38 1271

原创 别再随手调 string.Intern:.NET 字符串内驻留与 UTF-8 编码的真相

字符串是 .NET 里最容易被"想当然"的类型:看起来就是个字符数组,实际上内驻留、哈希随机化、UTF-16 与 UTF-8 的边界每一条都能咬人。这篇把机制讲清,把坑列全。

2026-10-25 09:03:23 1295

原创 ArrayPool 与 ObjectPool:省下的 GC 压力,和你悄悄赔上的正确性

池化是所有"高频短命对象"场景的第一反应:缓冲区、List<T>、临时byte[]。方向没错,但这两个池的语义是**“借用"而不是"创建”静默的正确性问题**:程序不抛异常,只是偶尔算出错的结果。

2026-10-24 09:10:40 1525

原创 异常的StackTrace是怎么来的?聊聊它的构造时机、保留手段与隐藏技巧

绝大多数 .NET 开发者每天都会看异常堆栈,但很少有人想过:这个字符串到底是什么时候生成的?为什么catch之后再看有时是null?为什么跨await之后堆栈会"断"?这篇文章把 StackTrace 的生命周期讲清楚。

2026-10-23 09:13:42 1769

原创 Channel&lt;T&gt; 用对了才是生产者-消费者银弹:机制、坑与选型

—可能丢数据,也可能读到重复项。这是典型的静默失效:上线很久、负载一变才暴露。

2026-10-22 09:10:45 1941

原创 ThreadPool 不是无限资源:线程注入、饥饿与 async 阻塞的真实代价

你在池线程上多阻塞一次,就要付出一次"等新线程被注入"的延迟。它返回的是"还能起多少线程",不是"还剩多少处理能力"。所以它既不参与 hill-climbing 统计,也不会被 MinThreads/MaxThreads 约束——用它是"隔离",不是"扩容"。这就是为什么同步阻塞的场景下延迟是"阶梯式"上涨的——你看到的不是排队,是在等下一根线程。一旦某个热点路径用了同步版,限流就从"排队"变成"占线程排队",并发度被线程数而不是信号量决定。几乎没有收益:请求本身已经跑在池线程上,多一次跳转只多一次排队。

2026-10-21 11:47:03 2087

原创 JIT 的去虚拟化与内联:哪些虚调用被悄悄拆掉了,哪些一直在原地打转

反过来,真正的成本往往来自"该拆没拆":把日志、校验、异常构造塞在热循环里,每个都因为体积超标而不内联,还各自带着参数打包。正确的做法不是加特性,是把热路径上的方法切小到能被内联的尺度,或者干脆手工展开一层。这才是"零成本抽象"该有的样子:不是靠特性求来的,是靠类型信息足够精确换来的。这也解释了一个常见困惑:为什么同一个方法,压测时快、线上偶尔抖——类型分布变了,守卫命中率就变了。构造函数注入拿到的是接口,JIT 看不到任何精确类型,连。写 C# 的性能优化,最容易犯的错是把"接口调用一定慢"和"加了。

2026-10-20 09:10:30 4638

原创 从分代预算到 DATAS:.NET GC 调优到底在调什么

关于 .NET GC 的资料里,“Server GC 吞吐高、Workstation GC 延迟低”"把GC.Collect去掉就好了"这类结论流传得比机制本身更广。结果是在容器里把打开、堆内存翻了三倍,或者照着旧文调却发现毫无变化。。理解这两个量怎么被算出来,DATAS 的取舍也就自然清楚了。

2026-10-19 09:09:23 5757

原创 .NET 里的 Span<T> 与 Memory<T>:哪些是零成本,哪些是静默的坑

Span 与 Memory 的分界线,本质是所有权与生命周期的分界线:能证明"活不过当前栈帧"的,用 Span;需要活过栈帧的,用 Memory。把这条线画清楚,比记住任何一个 API 都管用。

2026-10-18 12:37:39 6212

原创 System.Text.Json 源生成:三个“看起来已经生效“的静默失效

源生成的价值不在"更快",而在把序列化的类型契约提前到编译期。它的失效方式也正来源于此:契约没覆盖到的调用点会安静地退回反射。所以验收标准不该是"接口返回正常",而应该是"关掉反射开关之后,测试还能全绿"。

2026-10-18 12:30:20 3010

原创 .NET 的 lock 早就不是 Monitor 了:System.Threading.Lock 实测,18% 是真的,但有两个静默失效的坑

把改成,是 .NET 9 之后最常见的一次"顺手优化"。我把它在本机从头量了一遍:无竞争快 18% 是真的;但一有竞争,它和 Monitor 的差距就消失了,甚至在 32 线程过载时更差。更要紧的是,我在验证过程中撞到两个的坑——其中一个是"两把锁"。本文所有数字都是本机实测,环境、csproj、测量代码全部贴出,可复现。

2026-10-18 12:25:01 2987

原创 ValueTask 的真实账单:.NET 10 实测同步路径慢 2.5 倍、挂起多 8B,它到底还剩什么用

ValueTask 的历史包袱比它的价值更重:它诞生于"Task 分配太贵"的年代,而 JIT 的逃逸分析在 .NET 8~10 期间逐步把同步完成路径优化到了 0。库作者为百万级 QPS 手写 IVTS 的世界没有变,但普通开发者"高频路径无脑 ValueTask"的习惯,今天应该停一停了。欢迎在评论区晒你在自己业务上的实测——尤其是那个 19.4 对 48.9 的吞吐差,我很想看它在不同 CPU 架构上的形状。

2026-10-18 12:17:38 3027

原创 Async 状态机要搬进运行时了:.NET 10 Runtime Async 实测,快的地方快 1.5 倍,贵的地方贵 5 倍

runtime async 真正的价值,不在"现在快多少"。它把 async 从"每个语言各自实现的语法糖"变成了"运行时的一等公民":F#、VB、以后的新语言共享同一套挂起语义;调试器、Profiler、终于能看见真实的调用栈,而不是一堆;跨语言调用 async 方法不用再翻译 builder。代价也很清楚:状态布局从编译期推到了运行时。编译期能算死的东西,运行时就得现场算——那 470 B 就是这笔账的第一期账单。至于这笔账划不划算,等 .NET 11 把 R2R、PGO、AOT 都补齐了再看。

2026-10-18 11:33:55 3163

原创 【MVP深度】.NET MAF:从单 Agent 到可恢复的多 Agent 工作流

MAF 的方向是对的:它没有把 Agent 只当成一个更会聊天的接口,而是试图把 Agent 放进真实的软件工程体系里。对 .NET 开发者来说,最值得关注的不是某个具体 API,而是这套架构是否能让我们用熟悉的依赖注入、领域服务、工作流和可观测性,把 AI 能力变成可以维护的生产系统。我的建议是:先用一个只读场景跑通单 Agent,再引入工具调用;随后把确定性步骤抽成 Workflow,最后补齐审批、检查点和遥测。不要一上来就做“全自动多 Agent 平台”,那通常是复杂度的起点,不是成功的终点。

2026-09-02 12:03:36 14999

原创 攻克 ASP.NET Core Minimal API:中间件与过滤器的极致实战指南

不再调用。

2026-08-07 13:47:20 4428

原创 Avalonia 11.3 本地离线AI图像识别绑定Minimal API AI推理网关

本文仅聚焦Avalonia客户端异步图像控件绑定Minimal API离线AI推理网关这一细分知识点,依托Microsoft.Extensions.AI标准化图像分析接口,无需自研HTTP交互、数据序列化逻辑。相比传统桌面直连AI服务方案,该架构分离算力与展示层,边缘设备可复用服务端离线模型,兼顾界面流畅度与推理性能。在工业桌面质检、本地图像归档识别等场景具备落地价值,配合.NET 10 Native AOT编译可进一步缩减程序体积、提升启动速度。

2026-07-19 19:17:13 14506

原创 利用 Blazor 与 Native AOT 提升客户端应用的离线体验

通过 Blazor 与 Native AOT 的结合,能够显著提升客户端应用的离线体验。深入理解其原理,在实践中合理运用并避免常见坑点,开发者可以打造出更优秀的离线客户端应用,满足用户在不同网络环境下的使用需求。随着技术的不断进步,这种技术组合有望在离线应用开发领域发挥更大的作用。

2026-07-15 21:38:28 5431

原创 利用 Blazor 与 Native AOT 提升客户端应用的离线体验

通过 Blazor 与 Native AOT 的结合,能够显著提升客户端应用的离线体验。深入理解其原理,在实践中合理运用并避免常见坑点,开发者可以打造出更优秀的离线客户端应用,满足用户在不同网络环境下的使用需求。随着技术的不断进步,这种技术组合有望在离线应用开发领域发挥更大的作用。

2026-07-12 21:01:38 5403

原创 基于 Semantic Kernel 与.NET 11 构建智能云原生工作流

在中定义语义函数。// 简单的数据验证逻辑在中定义另一个语义函数,并组合工作流。// 简单的数据处理逻辑在Program.cs中构建和执行工作流。.Build();else基于 Semantic Kernel 与.NET 11 能够构建出智能、灵活的云原生工作流,满足现代企业复杂多变的业务需求。通过深入理解其原理,在实践中合理运用并避免常见坑点,开发者可以充分发挥这一技术组合的优势,为云原生应用带来更高的价值。

2026-07-11 20:24:39 5377

原创 借助 Microsoft.Extensions.AI 与 ASP.NET Core 10 实现智能 Web 应用故障预测

借助 Microsoft.Extensions.AI 与 ASP.NET Core 10 能够实现智能 Web 应用故障预测,有效提升应用的稳定性和可靠性。深入理解其原理,在实践中合理运用并避免常见坑点,可充分发挥这一技术组合的优势。随着人工智能和 Web 应用技术的发展,这种智能故障预测方式将在保障应用服务质量方面发挥更重要的作用。

2026-07-11 20:23:48 5294

python的可携带版本已经解决pip安装问题

python的可携带版本已经解决pip安装问题 直接在目录下使用python.exe -m pip 就可以直接安装包

2025-09-01

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除