C#已经存在了二十多年,每个新版本都会悄悄加入一些特性,让日常编码更简洁、更安全、更优雅。问题是大多数开发者还停留在五年前学到的编码方式中。
他们还在不停地输入 using (...) {},用命名空间的大括号堆砌文件,或者忘记空安全性和必需属性存在的意义。
本文讨论了5个现代C#技巧,可以减少代码冗余,让你的意图更加清晰。这些技巧并不复杂,也不小众,而是那种能够逐渐累积形成更清晰、更易维护代码的习惯。
1. 在is模式中使用解构 C#中的模式匹配已经发展成为该语言最具表现力的特性之一。一个很好的例子就是在is模式中使用解构。你无需先检查类型再赋值,而是可以在单个语句中获取所有需要的信息。
旧写法:
if (person is Employee e)
{
var id = e.Id;
var department = e.Department;
Console.WriteLine($"{id} - {department}");
}
这样写虽然可行,但感觉有些冗余。
更好的写法:
if (person is Employee(var id, var department))
{
Console.WriteLine($"{id} - {department}");
}
只要你的类型有解构器(比如记录类型就有),这种方法就能减少重复,让条件判断一目了然。你无需分两步操作,直接在if语句中声明你的意图。
2. 使用文件作用域命名空间简化代码文件
多年来,每个C#文件都以namespace MyApp { ... }开头,这迫使你进入不必要的缩进层级。一旦你的类变得庞大,屏幕的一半空间都会被用来维护大括号。
旧风格:
namespace MyApp.Core
{
public class UserService
{
// 所有内容都需要缩进
}
}
文件作用域命名空间风格:
namespace MyApp.Core;
public class UserService
{
// 简洁平整
}
这可能看起来是小事,但一旦你在整个代码库中应用它,每个文件都会立刻感觉更轻量。减少一层视觉噪音让你更容易专注于重要的事情:你的实际代码。
3. 在对象初始化器中优先使用必需属性以确保安全
你见过多少次User对象在你的系统中游荡,却缺少电子邮件、ID或其他绝对不应为空的属性?这正是required关键字大放异彩的地方。
没有required的情况:
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}
// 这能编译但是不完整
var user = new User { Name = "Alice" };
这能编译通过,但现在你有一个缺少电子邮件的User对象。这是一个潜在的bug。
使用required的情况:
public class User
{
public required string Name { get; init; }
public required string Email { get; init; }
}
var user = new User { Name = "Alice", Email = "alice@mail.com" };
编译器会强制要求设置Name和Email属性。没有捷径可走,不会忘记赋值。这就像在你的类型系统中内置了一个安全网,对于领域驱动设计特别有益,因为不完整的对象可能会破坏业务规则。
4. 使用声明式using var替代嵌套块 旧的using语句迫使你使用块作用域,这很快会变成令人畏惧的"金字塔厄运"。
旧风格:
using (var stream = new FileStream("file.txt", FileMode.Open))
{
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
现代风格:
using var stream = new FileStream("file.txt", FileMode.Open);
using var reader = new StreamReader(stream);
Console.WriteLine(reader.ReadToEnd());
资源仍然会自动释放,但你避免了混乱的嵌套。代码保持线性,这意味着更易于阅读和调试。
5. 在switch表达式中优先使用弃元_避免冗余的default Switch表达式让条件逻辑简洁明了,但许多开发者仍然用不必要的default关键字来堆砌它们。
冗长写法:
var result = status switch
{
200 => "OK",
404 => "Not Found",
default => "Unknown"
};
使用弃元更简洁:
var result = status switch
{
200 => "OK",
404 => "Not Found",
_ => "Unknown"
};
使用_清楚地表明你在处理"其他所有情况"。这不是你忘记考虑的兜底方案,而是一个有意识的回退处理。
你编写C#的时间越长,就越会意识到是那些小习惯造成了最大的不同。用文件作用域命名空间减少多余的大括号,用必需属性强制创建有效对象,或者用using var扁平化代码——这些可能看起来不炫酷,但随着时间的推移,它们会累积成更容易信任、更容易阅读的代码。
关键在于保持对语言发展的关注。这些特性大多已经存在多年,但许多代码库仍然停留在2010年代的模式中。你越早开始采用这些现代实践,你的代码库就能越早停止与你对抗,开始与你协作。