从 语法升级 到 实战示例 ,一次梳理三大版本高频特性
目录
-
C# 5.0 新特性
3.1 基于 TAP 的异步编程
3.2 在 Lambda 中使用循环变量 -
C# 6.0 新特性
4.1 自动属性初始化器
4.2 主构造器
4.3 字典初始化器
4.4 声明表达式
4.5 静态 using
4.6 await in catch/finally
4.7 异常过滤器
4.8 空值条件运算符 ?. 与 ?? -
C# 7.0 新特性
5.1 输出变量
5.2 模式匹配
5.3 元组与解构
5.4 局部函数
5.5 数字改进与二进制字面量
5.6 ref return 与 ref local
5.7 更多 Expression-bodied 成员
5.8 Throw 表达式
前言:为什么要学习新语法?
技术只有适用与否,没有新旧之分
——但懂得更多,你就拥有更多选择。
工作中我们经常遇到两类代码:
-
历史包袱:C# 3.0 甚至更早的写法,能跑但难维护。
-
现代语法:简洁、类型安全、具备更好的可读性与性能。
掌握 C# 5/6/7 不仅能写出更优雅的代码,还可在重构旧系统时游刃有余。本篇文章通过示例 + 场景分析,帮助你快速吸收每个版本的亮点特性。
C# 3.5 回顾:扩展方法的正确打开方式
虽然本文聚焦 5/6/7,但先用扩展方法热热身,因为它是后续很多语法糖的灵魂伴侣。
代码示例
public static class ConvertExtensions
{
// 将 object 安全地转成 string
public static string AsString(this object value) => value?.ToString() ?? string.Empty;
// 将 string 转成 int,失败则返回默认值
public static int AsInt32(this string value) =>
int.TryParse(value, out var i) ? i : 0;
}
使用方式:
int number = "123".AsInt32(); // 123
int zero = "abc".AsInt32(); // 0
优点
-
链式调用,逻辑自然。
-
摆脱
try...catch
嵌套,提高可读性。
C# 5.0 新特性
基于 TAP 的异步编程
async/await
让你像写同步代码一样编写异步逻辑,极大减少回调地狱。
// ✅ 推荐写法
static async Task DownloadAsync(Uri uri)
{
using var client = new HttpClient();
string html = await client.GetStringAsync(uri);
Console.WriteLine(html);
}
对比旧写法:
// ❌ 回调层层嵌套,可读性差
static void DownloadOld(Uri uri)
{
var client = new WebClient();
client.DownloadStringCompleted += (s, e) => Console.WriteLine(e.Result);
client.DownloadStringAsync(uri);
}
最佳实践
• 使用 ConfigureAwait(false)
在库代码中避免死锁。
• 优先返回 Task
/ Task<T>
而非 void
。
在 Lambda 中使用循环变量
C# 5 修复了循环捕获变量的“坑”。
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
int local = i; // 显式拷贝
actions.Add(() => Console.WriteLine(local));
}
执行后输出 0 1 2
,不再全部是 3
。
C# 6.0 新特性
自动属性初始化器
public class BlogPost
{
public long Id { get; } = 1;
public string Name { get; } = "Hello C# 6.0";
public string Title { get; private set; } = string.Empty;
}
• 少写一个构造函数,属性仍可在需要时 set
。
主构造器
public class BlogPost(long id, string name, string title)
{
public long Id { get; } = id;
public string Name { get; } = name;
public string Title { get; } = title;
}
让参数与字段绑定一目了然。
字典初始化器
var dict = new Dictionary<string, string>
{
["Home"] = "https://blog.csdn.net",
["Features"] = "C# 6 Highlights"
};
声明表达式
if (!int.TryParse(input, out var number))
{
Console.WriteLine("非法数字");
}
out var
直接声明,少了一次定义。
静态 using
using static System.Console;
WriteLine("无需前缀即可调用 WriteLine");
await in catch/finally
try
{
await DoWorkAsync();
}
catch (Exception ex)
{
await LogAsync(ex);
}
异常过滤器
catch (CustomException ex) when (ex.Level > 5)
{
// 仅处理严重错误
}
空值条件运算符 ?. 与 ??
var rank = user?.Rank ?? "No Rank";
一行代码避免多重 if (user != null)
判空。
C# 7.0 新特性
输出变量
if (int.TryParse(text, out var value))
{
Console.WriteLine($"合法数字:{value}");
}
无需提前声明 int value;
。
模式匹配
switch (shape)
{
case Circle c:
Console.WriteLine($"Circle r={c.Radius}");
break;
case Rectangle s when s.Length == s.Height:
Console.WriteLine("正方形");
break;
case Rectangle r:
Console.WriteLine($"矩形 {r.Length}x{r.Height}");
break;
case null:
throw new ArgumentNullException(nameof(shape));
default:
Console.WriteLine("未知形状");
break;
}
元组与解构
// 返回多个值
(string first, string last) GetName() => ("Tom", "Jerry");
// 解构
var (f, l) = GetName();
Console.WriteLine($"{f} {l}");
局部函数
int Fibonacci(int n)
{
if (n < 0) throw new ArgumentException();
return Fib(n).current;
(int current, int previous) Fib(int i)
=> i == 0 ? (1, 0) : (
Fib(i - 1).current + Fib(i - 1).previous,
Fib(i - 1).current);
}
数字改进与二进制字面量
int million = 1_000_000;
int flags = 0b1010_1011;
ref return 与 ref local
public ref int Find(int target, int[] nums)
{
for (var i = 0; i < nums.Length; i++)
if (nums[i] == target) return ref nums[i];
throw new IndexOutOfRangeException();
}
ref int place = ref Find(7, array);
place = 9; // 修改原数组
更多 Expression-bodied 成员
class Person(string name)
{
public string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
~Person() => Console.WriteLine("Finalized");
}
Throw 表达式
string GetFirst(string[] arr) =>
(arr?.Length > 0) ? arr[0] : throw new InvalidOperationException("空数组");
小结与最佳实践
-
从可读性出发:善用模式匹配、元组、解构让意图更清晰。
-
从性能出发:异步 I/O +
ConfigureAwait(false)
+ValueTask<T>
(C# 7.0 之后)减少上下文切换与堆分配。 -
从可维护性出发:局部函数、静态 using、空值运算符让代码更 DRY(Don’t Repeat Yourself)。
在重构旧项目时,可以渐进式引入新语法:
• 先用 nameof
、??
、?.
安全替换魔法字符串与判空;
• 再将老式 Begin/End
异步重写为 async/await
;
• 最后尝试使用模式匹配、元组重构 Core 逻辑。
互动:你的点赞就是对作者最大的支持!
如果本文对你有所启发:
-
点个 👍 让更多人看到;
-
关注专栏,第一时间获取 .NET 最新干货;
-
评论区聊聊你最喜欢的 C# 新特性 ,一起切磋提升!
知识的世界无限大,让我们一起保持学习的热情!