无论你已经编写.NET代码十年,还是刚刚发布第一个生产环境API,往往是那些小习惯带来了最大的改变。干净、高性能的代码很少来自大刀阔斧的重写,而是源于开发者每天做出的无数微小决策。
本博客将开启一个系列,每次聚焦5个可操作的.NET见解,每个见解都基于实际使用场景、性能考量和长期代码健康。没有空洞的理论,只有精准、简洁且能立即应用的技巧。
让我们进入今天的5个要点。
is not null
而非!= null
,实现更安全、更智能的空值检查
在启用了可空引用类型的现代C#中,编写if (user is not null)
不仅仅是风格问题,它更安全、更清晰且更智能。重要原因:
is not null
模式改进了流分析。它帮助编译器更准确地确定变量的可空性,减少在可空感知上下文中的误报警告。if (user is not null && user.IsActive)
{
// 安全:编译器知道此处'user'不为空
}
对比之下:
if (user != null && user.IsActive)
{
// 可能仍会引发可空警告
}
is not null
不能被重载,而!= null
在用户定义的类型中可以被重载。这使得is not null
成为更可靠和可预测的选择。class WeirdClass
{
public static bool operator !=(WeirdClass? a, object? b) => false;
public static bool operator ==(WeirdClass? a, object? b) => true;
}
var weird = new WeirdClass();
Console.WriteLine(weird != null); // false — 误导性结果!
Console.WriteLine(weird is not null); // true — 正确结果!
在启用可空引用类型的项目中,应始终优先使用is not null
,尤其是在以下情况:
==
/!=
的对象Parallel.For
,但要知道何时避免使用它
Parallel.For
可以通过在多个线程间分配工作来显著加快CPU密集型操作的速度。但它并非在任何情况下都是正确的选择。适用场景:
Parallel.For(0, 1000, i =>
{
// 繁重的CPU密集型任务,如加密或图像处理
ProcessChunk(i);
});
这可以通过利用多个内核来减少执行时间。
应避免使用Parallel.For
的情况:
仅在以下情况使用Parallel.For
:
最好对两种方式进行基准测试以确认。否则,为了清晰性和可预测性,坚持使用for
或foreach
。
static
(C# 12)
在Lambda中捕获外部变量可能导致隐藏的内存分配。从C# 12开始,你可以将Lambda标记为static
以消除捕获,使它们更快且无分配。var ids = items.Select(static item => item.Id).ToArray();
static
关键字确保不会创建闭包,并且如果意外访问任何外部变量,你会得到编译时错误。
示例:
int a = 5;
int b = 10;
// 使用元组交换
(a, b) = (b, a);
只要两边可赋值,这适用于任何类型。
为什么更好:
await
以获得更快的代码路径
如果可以直接返回Task
而无需await
,特别是在叶子级方法中,你可以避免async
引入的状态机,从而使代码更快。// 如果内部不需要await,这样更好
public Task<string> GetDataAsync() => httpClient.GetStringAsync(url);
对比之下:
// 由于async状态机,速度较慢
public async Task<string> GetDataAsync()
{
return await httpClient.GetStringAsync(url);
}
这种细微的差异在高性能场景或紧密循环中会累积起来。每次你await
一个Task
时,在处理可能的结果切换过程中,底层会创建一个新类。如果不需要,何必添加这个额外的类呢?
这五个习惯可能看起来微不足道,但它们反映了对.NET底层工作原理的更深入理解。如果你在日常开发中采用其中一两个,你将开始在代码清晰度、性能和可维护性方面看到收益,并使自己成为更出色的.NET开发者。