C#语法糖(按照实用性排序)
这里整理了C#日常开发最高频、最能提升代码简洁度的语法糖按实用度排序语法糖本质是编译器帮你生成等价的完整代码不影响运行性能只负责让代码更短、更易读、更少出错。一、空安全系列每天都用优先级最高彻底解决层层判空的冗余代码是C#最实用的语法特性没有之一。1. 空条件运算符?./?[]访问对象的属性/方法/索引前自动判空对象为null时直接返回null不会抛空引用异常。// 原始写法stringiconnull;if(itemInfo!nullitemInfo.Data!null)iconitemInfo.Data.Icon;// 语法糖写法stringiconitemInfo?.Data?.Icon;// 数组/索引同理int?firstIditemList?[0]?.Id;2. 空合并运算符??左边值为null时取右边的默认值专门处理“拿不到就用默认值”的场景。// 原始写法stringnameitem.Name;if(namenull)name未知道具;// 语法糖写法stringnameitem.Name??未知道具;// 配合?. 一起用intcountitemInfo?.Num??0;3. 空合并赋值??左边变量为null时才把右边的值赋给它简化延迟初始化。// 原始写法if(infosnull)infosnewListItemInfo();// 语法糖写法infos??newListItemInfo();4. 空包容运算符!告诉编译器“这个对象我确定不会为null不用报警告”Unity开发中非常常用很多Unity对象生命周期由引擎控制编译器无法判断。// 明确知道GetComponent一定能拿到消除空警告varcontrollergameObject.GetComponentItemController()!;二、类型与声明简化1. 隐式类型var编译器自动推导变量类型代码更简洁尤其适合长类型名。// 原始写法Dictionaryint,ItemInfoitemDictnewDictionaryint,ItemInfo();// 语法糖写法varitemDictnewDictionaryint,ItemInfo();注意var仍然是强类型编译后和写全类型完全等价不是动态类型。2. 目标类型推导new()C# 9声明变量时右边new可以省略类型编译器自动匹配左边的类型进一步简化。// 原始写法ListItemDatalistnewListItemData();// 语法糖写法ListItemDatalistnew();3. 值元组ValueTuple多返回值神器方法可以直接返回多个值不用写out参数、不用自定义结构体/类游戏逻辑中极其常用。// 定义方法直接返回多个结果public(boolisSuccess,intcount,intitemId)CheckItem(inttype){return(true,99,1001);}// 调用解构接收var(ok,num,id)CheckItem(1);4. 解构赋值可以把对象、元组拆成多个变量一次性赋值。// 元组解构var(id,name,num)(1001,生命药水,10);// 自定义类也可以支持解构写Deconstruct方法publicvoidDeconstruct(outintid,outstringname,outintnum){idId;nameName;numNum;}三、字符串处理1. 字符串插值$替代string.Format直接在字符串里嵌变量和表达式可读性极强。// 原始写法stringmsgstring.Format(获得道具{0} x{1},itemName,count);// 语法糖写法stringmsg$获得道具{itemName}x{count};// 还可以直接写表达式stringtip$剩余数量{info.Num-cost};2. 原始字符串字面量...C# 11写多行文本、JSON、SQL时不用转义引号和换行非常干净。stringjson{id:1001,name:生命药水,num:10};四、成员与方法简化1. 表达式体成员单行的方法、属性、构造函数都可以用简写去掉大括号和return。// 原始写法publicintTotalNum{get{returnprotos.Sum(oo.Num);}}publicstringGetDesc(){returnData.Description;}// 语法糖写法publicintTotalNumprotos.Sum(oo.Num);publicstringGetDesc()Data.Description;2. 扩展方法给已有的类型“新增”方法不用修改原类不用继承是LINQ的基础自己写工具方法也极其好用。// 给int写一个扩展方法publicstaticclassIntExt{publicstaticboolIsPositive(thisintnum)num0;}// 调用像原生方法一样用if(count.IsPositive()){...}3. 可选参数 命名参数方法参数给默认值调用时可以跳过部分参数还可以按名字传参不用记参数顺序。// 定义publicvoidAddItem(intitemId,intnum1,boolshowTiptrue){...}// 调用只传itemId其他用默认AddItem(1001);// 命名传参只改showTip不用管顺序AddItem(1001,showTip:false);4. 局部函数在方法内部定义小函数只在当前方法内可见比委托更干净性能更好。publicvoidProcessItems(ListItemitems){// 内部辅助函数boolIsValid(Itemitem)item.Num0item.ExpTime0;foreach(variteminitems){if(IsValid(item)){...}}}五、LINQ 集合操作集合处理神器LINQ是C#处理集合的大杀器几乎所有集合遍历、筛选、转换都可以用它一行写完替代大量foreach循环。以下是最高频的10个方法ListItemInfoinfos...;// 1. 筛选WherevarvalidItemsinfos.Where(xx.Num0).ToList();// 2. 转换/映射SelectvarallItemIdsinfos.Select(xx.Data.Id).ToList();// 3. 取第一个/第一个默认First / FirstOrDefaultvarfirstIteminfos.First(xx.Data.Id1001);variteminfos.FirstOrDefault(xx.Data.Id1001);// 4. 是否存在AnyboolhasIteminfos.Any(xx.Data.Id1001);// 5. 全部满足AllboolallEnoughinfos.All(xx.Num5);// 6. 计数/求和Count / SuminttotalCountinfos.Sum(xx.Num);intrareCountinfos.Count(xx.Data.Grade3);// 7. 排序OrderBy / OrderByDescendingvarsortedinfos.OrderByDescending(xx.Data.Grade).ToList();// 8. 转列表/数组ToList() / ToArray()// 把IEnumerable转为实际集合最常用// 9. 分组GroupByvargroupsinfos.GroupBy(xx.Data.Type);// 10. 字典转换ToDictionaryvardictinfos.ToDictionary(xx.Data.Id,xx);六、模式匹配替代冗余if-else1.is类型模式 变量声明判断类型的同时直接声明变量不用二次强转。// 原始写法if(protoisLists){Listslist(Lists)proto;...}// 语法糖写法if(protoisListslist){// 直接用list变量itemslist.Items.ToList();}2.switch表达式C# 8把switch语句写成表达式更简洁适合多分支返回值的场景。// 原始写法stringGetQualityName(intgrade){switch(grade){case1:return普通;case2:return稀有;case3:return史诗;default:return未知;}}// 语法糖写法stringGetQualityName(intgrade)gradeswitch{1普通,2稀有,3史诗,_未知};3. 属性模式直接匹配对象的属性值写复杂分支判断非常干净。stringGetItemDesc(ItemInfoinfo)infoswitch{{Num:0}未拥有,{Data.Grade:3,Num:10}大量稀有道具,{Data.Type:2}材料类道具,_普通道具};七、其他高频实用1.nameof运算符获取变量、类、方法、属性的名字字符串避免硬编码改名字时编译器自动同步。// 原始写法Debug.LogError(ItemController 初始化失败);// 语法糖写法改类名时自动跟着变Debug.LogError(${nameof(ItemController)}初始化失败);2. 三元运算符?:最基础也最常用的单行条件赋值。// 原始写法stringtext;if(num0)text充足;elsetext不足;// 语法糖写法stringtextnum0?充足:不足;3. 索引与范围^/..C# 8快速取数组/集合的末尾元素和片段。int[]arr{1,2,3,4,5};intlastarr[^1];// 最后一个元素 5intsecondLastarr[^2];// 倒数第二个 4int[]partarr[1..3];// 索引1到2的元素 {2,3}4.using声明C# 8自动释放IDisposable对象不用写大括号作用域到当前方法结束自动释放。// 原始写法using(varstreamnewFileStream(path,FileMode.Open)){...}// 语法糖写法usingvarstreamnewFileStream(path,FileMode.Open);// 方法结束自动释放5.record记录类型C# 9专门用来做不可变数据载体自带值比较、ToString、拷贝非常适合传配置、传数据快照。// 定义一行搞定自动生成构造函数、属性、Equals、ToStringpublicrecordItemSnapshot(intId,stringName,intNum);// 使用varsnapnewItemSnapshot(1001,药水,10);varnewSnapsnapwith{Num20};// 拷贝并修改部分字段学习优先级建议第一梯队必掌握空安全系列、字符串插值、var、LINQ基础、表达式体成员第二梯队大幅提效值元组、扩展方法、is模式匹配、switch表达式、nameof第三梯队按需使用record、索引范围、原始字符串、属性模式这些特性在Unity 2021及以上版本都已完整支持放心用在项目里即可。