.NET已经进化,你的编码方式也该与时俱进。如果你还在像2015年那样随处使用Tuple<>和dynamic,这篇文章就是你的警钟。这些不是语法噱头,而是资深工程师应该依赖的实用习惯,用于编写快速、安全且可维护的代码。忽视它们,后果自负。
下面分享5个改变我编写.NET方式的代码技巧,它们从今天起就能提升你的工作质量。
1. 在泛型中使用notnull约束实现更安全的契约
如果你正在编写泛型代码,可能已经熟悉where T : class或where T : struct。但现代C#新增了一个强大工具:where T : notnull。
此约束强制要求T不能是可空引用类型或可空值类型。这对于防御性编码意义重大。当你的逻辑需要实际值时,不再需要猜测调用方是否传入了T?。
public static T FirstOrThrow<T>(IEnumerable<T> items)
where T : notnull
{
foreach (var item in items)
return item;
throw new InvalidOperationException("Sequence was empty.");
}
这能提前保护你的逻辑,并与可空引用类型无缝配合。你不再需要为编译器能在类型层面守护的东西编写过多文档或添加运行时检查。
专业提示:结合[DisallowNull]和[MaybeNull]注解可实现完整的契约级清晰度。
2. 使用全局using指令清理每个文件
是否曾在几十个文件中反复键入相同的using System.Linq;或using System.Collections.Generic;?这是冗余工作,现代.NET提供了解决方案。
引入全局using。只需创建如GlobalUsings.cs的文件:
global using System;
global using System.Linq;
global using MyProject.Shared.Extensions;
就这样。这些using语句现在整个项目都可用。每个文件不再有额外杂乱内容,不再浪费击键次数。
专业提示:将此与文件夹级.editorconfig范围结合,用于API、UI或领域模型等共享层,代码库立即可读性更强。
3. 停止使用dynamic,你写的是C#,不是YavaScript(懂的都懂)
是的,在某些边缘场景中dynamic有意义,比如COM互操作、旧XML库或鸭子类型实验。但在实际生产代码中?它是性能陷阱和类型安全的手榴弹。
dynamic x = GetSomething();
var result = x.SomeProperty + 42; // 希望这能编译
没有编译时安全性。没有性能优化,没有IntelliSense。它在底层使用反射将所有事情推迟到运行时。如果我有什么比JavaScript更讨厌的东西,那就是反射。除非被迫,我拒绝使用两者。
如果你发现自己使用dynamic,问问为什么。接口、模式匹配或源生成器能否替代它?几乎总是答案是肯定的。
另外,如果只是为了避免少量样板代码而使用dynamic,那你就像在写JavaScript一样写C#。别这样。
4. 优先使用ValueTuple替代经典Tuple实现可读且无分配的分组
经典的Tuple<T1, T2>类型仍在遗留代码库中漂浮,但它们冗长、在堆上装箱且纯粹丑陋。
// 旧方式
Tuple<int, string> result = Tuple.Create(1, "Success");
// 现代方式
(int id, string status) result = (1, "Success");
ValueTuple是结构体,因此避免堆分配。但更重要的是,它具名成员,使你的意图更清晰。
Console.WriteLine(result.status); // 不再是Item2
还有用的特性:ValueTuple与模式匹配和解构完美搭配:
var (id, status) = GetResult();
这是让代码库立刻感觉像是近十年编写的小升级之一。
5. 使用ArgumentNullException.ThrowIfNull()快速清晰地失败
在C# 10中,.NET终于添加了我们多年来手动编写的辅助方法:
ArgumentNullException.ThrowIfNull(user);
它简洁,告诉编译器此后变量不为空(得益于[NotNull]属性),并自动生成参数名。
对比传统方式:
if (user == null)
throw new ArgumentNullException(nameof(user));
现在这是一行代码。它表达力强,快速。这就是现代C#应有的感觉。
额外好处:因为这在null时无条件抛出,编译器知道调用后的任何代码都在处理非空user。这意味着在可空感知上下文中更少噪音和误报警告。
这些技巧单独看可能并不惊天动地。但将它们叠加在一起——更安全的泛型、更清晰的异常流、零开销元组、整洁的文件以及dynamic的终结——你将得到一个读起来像是由懂行之人编写的代码库。
最棒的部分?这些不是时尚技巧。它们只是现代.NET中的智能默认方式。想在开口前就看起来像资深开发者吗?从这样编写代码开始。