C#语法糖(按照实用性排序)

这里整理了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 }; // 拷贝并修改部分字段

学习优先级建议

  1. 第一梯队(必掌握):空安全系列、字符串插值、var、LINQ基础、表达式体成员
  2. 第二梯队(大幅提效):值元组、扩展方法、is模式匹配、switch表达式、nameof
  3. 第三梯队(按需使用):record、索引范围、原始字符串、属性模式

这些特性在Unity 2021及以上版本都已完整支持,放心用在项目里即可。

相关推荐
z落落2 小时前
C#五大加密算法(AES、DES、MD5、RSA、SHA)
开发语言·c#
孝顺的书包2 小时前
将《C# 调用非托管程序》一文中最后一种方法修改如下(篇幅原因简化了注释):
开发语言·c#
辰三2 小时前
统信 UOS + GBase 8s 国产化环境部署实战:从虚拟机到数据库连接完整指南
linux·c#
标致的钢铁侠2 小时前
c# 温故而知新: 线程篇(一)
java·jvm·c#
蜗牛~turbo3 小时前
金蝶云星空的网络控制设置
开发语言·c#·金蝶·erp·云星空·k3 cloud
avi91114 小时前
[AI教做人]CinemachineCamera 各项调整配置参数入门 + Profiler
unity·游戏开发·camera·cinemachine·visual camera·镜头配置
huaqianzkh4 小时前
DevExpress TreeList 右键菜单踩坑复盘:空白区域正常、节点右键弹出控件自带菜单解决方案
c#
贪玩的蛋挞15 小时前
C#与闭包
开发语言·c#
忧郁的紫菜20 小时前
基础实现:单篇 Markdown 转 Word
开发语言·c#·word