5个被严重低估的 C# 特性,让防御性代码彻底消失
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
很多老派 .NET 开发者都有一个共同习惯:写一堆防御性代码。 方法开头先来三行 null 检查,构造函数里各种参数验证,属性全部 private set “以防万一”,单元测试也围绕“不变量有没有被破坏”反复验证。 但说实话,这些代码大多不是业务逻辑,而是对“可能出错”的恐惧。 从 C# 10 到 C# 13,语言本身已经进化到一个新的阶段。很多过去只能在运行时做的防御,现在可以在编译期直接解决。这不是语法糖,而是类型系统和流分析能力的提升。 下面这 5 个特性,如果用好,能明显减少守卫代码,让系统更清晰、更可靠。 1. required 成员:把不变量交给编译器过去我们经常会写出这样的代码: 如果 C# 11 引入了 只要少写一个属性,编译器立刻报错。 这背后的价值很大:让无效状态无法被表示。 你不再需要在每个方法里写: 因为类型已经保证它存在。 官方说明见: ① https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members 2. init-only 属性:真正的“构造后不可变”很多人以为 这其实是假不可变。类内部随时可以改。
对象初始化之后,再赋值就会直接编译错误: 这带来的不是“语法优雅”,而是对象图稳定性。尤其在高并发系统中,不可变对象意味着线程安全更简单,行为更可预测。 官方文档: ② https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init 3. ConfigureAwaitOptions:异步语义变得可控过去我们只有: 很多人用它,但并不真正理解它。 .NET 8 引入了 在管道或框架级代码中,这非常有用: 你可以清楚表达“异常如何传播”“是否继续执行”等语义,而不是靠约定。 相关说明可参考 .NET 博客文章: ③ https://devblogs.microsoft.com/dotnet/ 4. CallerArgumentExpression:让守卫代码自解释传统参数检查通常这样写: 错误信息基本靠 C# 11 提供了 调用: 异常信息会自动变成: 这在验证库中尤其好用: 守卫逻辑变得更干净,错误信息也更有上下文。 官方文档: ④ https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerargumentexpressionattribute 5. 可空性流属性:告诉编译器你的真实意图开启可空引用类型之后,我们经常遇到这种情况: 虽然逻辑上是安全的,但编译器不知道。 这时候可以用 现在,只要返回 true,编译器就相信 这对于公共库尤其重要,可以大幅减少 API 使用者的冗余 null 检查。 官方说明: ⑤ https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis 防御性代码 vs 声明式意图防御性代码从来不是目标,目标是正确性。 现代 C# 做的事情很简单:把“你希望成立的条件”写进类型系统,而不是写进 if 语句。 综合示例:五个特性协同工作你会发现,这里没有: 没有后续 null 检查。 没有对象构造后的二次校验。 没有防止属性被篡改的守卫逻辑。 因为类型已经表达了不变量。 架构层面的影响当团队一致使用这些特性时,你会看到一些很明显的变化: DTO 初始化错误明显减少。 空引用异常几乎消失。 守卫库代码越来越少。 单元测试更专注业务行为,而不是参数校验。 这不是“代码看起来更现代”,而是结构上的简化。系统规模越大,这种简化的复利效应越明显。 结语现代 C# 的核心思想是: 不要假设开发者能记住所有不变量。 让语言帮你记住。 当类型系统足够精确,运行时就不需要那么多防御。 代码不只是能编译,而是能长期演进、能在规模下稳定运行。这才是语言进化真正的意义。 参考资料① Microsoft. C# 11 required membershttps://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members ② Microsoft. Init-only settershttps://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init ③ Microsoft. .NET Bloghttps://devblogs.microsoft.com/dotnet/ ④ Microsoft. CallerArgumentExpressionAttributehttps://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.callerargumentexpressionattribute ⑤ Microsoft. Nullable flow attributeshttps://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis ⑥ Microsoft. .NET Bloghttps://devblogs.microsoft.com/dotnet/ 阅读原文:原文链接 该文章在 2026/3/4 9:49:00 编辑过 |
关键字查询
相关文章
正在查询... |