这里整理了C#日常开发最高频、最能提升代码简洁度的语法糖,按实用度排序
语法糖本质是编译器帮你生成等价的完整代码,不影响运行性能,只负责让代码更短、更易读、更少出错。
一、空安全系列(每天都用,优先级最高)
彻底解决层层判空的冗余代码,是C#最实用的语法特性,没有之一。
1. 空条件运算符 ?. / ?[]
访问对象的属性/方法/索引前自动判空,对象为null时直接返回null,不会抛空引用异常。
csharp
// 原始写法
string icon = null;
if (itemInfo != null && itemInfo.Data != null)
icon = itemInfo.Data.Icon;
// 语法糖写法
string icon = itemInfo?.Data?.Icon;
// 数组/索引同理
int? firstId = itemList?[0]?.Id;
2. 空合并运算符 ??
左边值为null时,取右边的默认值,专门处理"拿不到就用默认值"的场景。
csharp
// 原始写法
string name = item.Name;
if (name == null) name = "未知道具";
// 语法糖写法
string name = item.Name ?? "未知道具";
// 配合?. 一起用
int count = itemInfo?.Num ?? 0;
3. 空合并赋值 ??=
左边变量为null时,才把右边的值赋给它,简化延迟初始化。
csharp
// 原始写法
if (infos == null)
infos = new List<ItemInfo>();
// 语法糖写法
infos ??= new List<ItemInfo>();
4. 空包容运算符 !
告诉编译器"这个对象我确定不会为null,不用报警告",Unity开发中非常常用(很多Unity对象生命周期由引擎控制,编译器无法判断)。
csharp
// 明确知道GetComponent一定能拿到,消除空警告
var controller = gameObject.GetComponent<ItemController>()!;
二、类型与声明简化
1. 隐式类型 var
编译器自动推导变量类型,代码更简洁,尤其适合长类型名。
csharp
// 原始写法
Dictionary<int, ItemInfo> itemDict = new Dictionary<int, ItemInfo>();
// 语法糖写法
var itemDict = new Dictionary<int, ItemInfo>();
注意:
var仍然是强类型,编译后和写全类型完全等价,不是动态类型。
2. 目标类型推导 new()(C# 9)
声明变量时,右边new可以省略类型,编译器自动匹配左边的类型,进一步简化。
csharp
// 原始写法
List<ItemData> list = new List<ItemData>();
// 语法糖写法
List<ItemData> list = new();
3. 值元组 ValueTuple:多返回值神器
方法可以直接返回多个值,不用写out参数、不用自定义结构体/类,游戏逻辑中极其常用。
csharp
// 定义方法:直接返回多个结果
public (bool isSuccess, int count, int itemId) CheckItem(int type)
{
return (true, 99, 1001);
}
// 调用:解构接收
var (ok, num, id) = CheckItem(1);
4. 解构赋值
可以把对象、元组拆成多个变量一次性赋值。
csharp
// 元组解构
var (id, name, num) = (1001, "生命药水", 10);
// 自定义类也可以支持解构(写Deconstruct方法)
public void Deconstruct(out int id, out string name, out int num)
{
id = Id; name = Name; num = Num;
}
三、字符串处理
1. 字符串插值 $""
替代string.Format,直接在字符串里嵌变量和表达式,可读性极强。
csharp
// 原始写法
string msg = string.Format("获得道具:{0} x{1}", itemName, count);
// 语法糖写法
string msg = $"获得道具:{itemName} x{count}";
// 还可以直接写表达式
string tip = $"剩余数量:{info.Num - cost}";
2. 原始字符串字面量 """..."""(C# 11)
写多行文本、JSON、SQL时不用转义引号和换行,非常干净。
csharp
string json = """
{
"id": 1001,
"name": "生命药水",
"num": 10
}
""";
四、成员与方法简化
1. 表达式体成员 =>
单行的方法、属性、构造函数都可以用=>简写,去掉大括号和return。
csharp
// 原始写法
public int TotalNum
{
get { return protos.Sum(o => o.Num); }
}
public string GetDesc()
{
return Data.Description;
}
// 语法糖写法
public int TotalNum => protos.Sum(o => o.Num);
public string GetDesc() => Data.Description;
2. 扩展方法
给已有的类型"新增"方法,不用修改原类,不用继承,是LINQ的基础,自己写工具方法也极其好用。
csharp
// 给int写一个扩展方法
public static class IntExt
{
public static bool IsPositive(this int num) => num > 0;
}
// 调用:像原生方法一样用
if (count.IsPositive()) { ... }
3. 可选参数 + 命名参数
方法参数给默认值,调用时可以跳过部分参数,还可以按名字传参,不用记参数顺序。
csharp
// 定义
public void AddItem(int itemId, int num = 1, bool showTip = true) { ... }
// 调用:只传itemId,其他用默认
AddItem(1001);
// 命名传参:只改showTip,不用管顺序
AddItem(1001, showTip: false);
4. 局部函数
在方法内部定义小函数,只在当前方法内可见,比委托更干净,性能更好。
csharp
public void ProcessItems(List<Item> items)
{
// 内部辅助函数
bool IsValid(Item item) => item.Num > 0 && item.ExpTime == 0;
foreach (var item in items)
{
if (IsValid(item)) { ... }
}
}
五、LINQ 集合操作(集合处理神器)
LINQ是C#处理集合的大杀器,几乎所有集合遍历、筛选、转换都可以用它一行写完,替代大量foreach循环。
以下是最高频的10个方法:
csharp
List<ItemInfo> infos = ...;
// 1. 筛选:Where
var validItems = infos.Where(x => x.Num > 0).ToList();
// 2. 转换/映射:Select
var allItemIds = infos.Select(x => x.Data.Id).ToList();
// 3. 取第一个/第一个默认:First / FirstOrDefault
var firstItem = infos.First(x => x.Data.Id == 1001);
var item = infos.FirstOrDefault(x => x.Data.Id == 1001);
// 4. 是否存在:Any
bool hasItem = infos.Any(x => x.Data.Id == 1001);
// 5. 全部满足:All
bool allEnough = infos.All(x => x.Num >= 5);
// 6. 计数/求和:Count / Sum
int totalCount = infos.Sum(x => x.Num);
int rareCount = infos.Count(x => x.Data.Grade >= 3);
// 7. 排序:OrderBy / OrderByDescending
var sorted = infos.OrderByDescending(x => x.Data.Grade).ToList();
// 8. 转列表/数组:ToList() / ToArray()
// (把IEnumerable转为实际集合,最常用)
// 9. 分组:GroupBy
var groups = infos.GroupBy(x => x.Data.Type);
// 10. 字典转换:ToDictionary
var dict = infos.ToDictionary(x => x.Data.Id, x => x);
六、模式匹配(替代冗余if-else)
1. is 类型模式 + 变量声明
判断类型的同时直接声明变量,不用二次强转。
csharp
// 原始写法
if (proto is Lists)
{
Lists list = (Lists)proto;
...
}
// 语法糖写法
if (proto is Lists list)
{
// 直接用list变量
items = list.Items.ToList();
}
2. switch 表达式(C# 8)
把switch语句写成表达式,更简洁,适合多分支返回值的场景。
csharp
// 原始写法
string GetQualityName(int grade)
{
switch (grade)
{
case 1: return "普通";
case 2: return "稀有";
case 3: return "史诗";
default: return "未知";
}
}
// 语法糖写法
string GetQualityName(int grade) => grade switch
{
1 => "普通",
2 => "稀有",
3 => "史诗",
_ => "未知"
};
3. 属性模式
直接匹配对象的属性值,写复杂分支判断非常干净。
csharp
string GetItemDesc(ItemInfo info) => info switch
{
{ Num: 0 } => "未拥有",
{ Data.Grade: >= 3, Num: > 10 } => "大量稀有道具",
{ Data.Type: 2 } => "材料类道具",
_ => "普通道具"
};
七、其他高频实用
1. nameof 运算符
获取变量、类、方法、属性的名字字符串,避免硬编码,改名字时编译器自动同步。
csharp
// 原始写法
Debug.LogError("ItemController 初始化失败");
// 语法糖写法:改类名时自动跟着变
Debug.LogError($"{nameof(ItemController)} 初始化失败");
2. 三元运算符 ?:
最基础也最常用的单行条件赋值。
csharp
// 原始写法
string text;
if (num > 0) text = "充足";
else text = "不足";
// 语法糖写法
string text = num > 0 ? "充足" : "不足";
3. 索引与范围 ^ / ..(C# 8)
快速取数组/集合的末尾元素和片段。
csharp
int[] arr = { 1, 2, 3, 4, 5 };
int last = arr[^1]; // 最后一个元素 = 5
int secondLast = arr[^2]; // 倒数第二个 = 4
int[] part = arr[1..3]; // 索引1到2的元素 = {2,3}
4. using 声明(C# 8)
自动释放IDisposable对象,不用写大括号,作用域到当前方法结束自动释放。
csharp
// 原始写法
using (var stream = new FileStream(path, FileMode.Open))
{
...
}
// 语法糖写法
using var stream = new FileStream(path, FileMode.Open);
// 方法结束自动释放
5. record 记录类型(C# 9)
专门用来做不可变数据载体,自带值比较、ToString、拷贝,非常适合传配置、传数据快照。
csharp
// 定义一行搞定,自动生成构造函数、属性、Equals、ToString
public record ItemSnapshot(int Id, string Name, int Num);
// 使用
var snap = new ItemSnapshot(1001, "药水", 10);
var newSnap = snap with { Num = 20 }; // 拷贝并修改部分字段
学习优先级建议
- 第一梯队(必掌握):空安全系列、字符串插值、var、LINQ基础、表达式体成员
- 第二梯队(大幅提效):值元组、扩展方法、is模式匹配、switch表达式、nameof
- 第三梯队(按需使用):record、索引范围、原始字符串、属性模式
这些特性在Unity 2021及以上版本都已完整支持,放心用在项目里即可。