c#各大版本重要变更

2023-04-12

说明

c#11已经发布了,近些年,c#不断推出新版本,新功能、新语法糖,相信大家在项目中或多或少都能看到其身影。这几天闲着没事整理了一下c#6到c#10项目中常用的新特性、语法糖,希望能够有个印象吧

6.0

nameof表达式

nameof 表达式可生成变量、类型或成员的名称作为字符串常量,当操作数是类型或命名空间时,生成的名称不是完全限定的。nameof在编译中是没有任何意义的。用的比较少吧,最常见的就是定义常量了

image-20230129172436452

?.、?[] null传播器

通常当一个对象为null时,我们去调用其属性或方法,程序就会报空异常。这时我们就不得不主动捕获异常或者提前检验对象是否为null。null传播器的出现可以让我们减少书写不必要的代码

假设这里有一段程序,我们明眼一看就是有问题的

image-20230129174616415

那么我们应该怎么处理呢?处理异常或者做空判断

上述方法是可以解决的,而null传播器就是帮助我们简化做空判断的,在一条语句中,如果对象为null则立即返回null,不会继续往下调用。如下我们可以看到null传播器确实可以帮助我们节省很多if判断,?[]还可作用于数组、集合、字典按索引、key取值的情况

image-20230129180635900

字符串内插

我们常见的字符串链接方式有如下几种:

字符串内插也是字符串连接的一种,使用字符串内插可以让我们的代码看起来更简洁更直观一点,格式:$"xxx{value}xxx"

当文本有{}冲突时,可以使用{}进行转义,有""冲突时,可以使用{{{}}}进行处理

7.0

throw可作为表达式使用
元组赋值、析构、比较,弃元

我们先看一下以前的元组Tuple——声明复杂,取值不明确。首先要new Tuple还要指定泛型,取值只能通过Item1、Item2、Item3...

优化过后,元组声明更简便,取值也可以通过析构、具名等方式让代码看起来更直观易懂。

同时满足以下两个条件时,两个元组可进行比较:具有相同数量的元素、每个元组位置上的元素类型一致

元组弃元,指的是在元组析构时我们只需要其中某些元素,而其他元素我们是不需要的,这时候就可以使用弃元了,如下我们只需要其中money元素:

本地函数

本地函数即函数内的函数,本地函数内可以共享函数外的变量,通常用于处理一系列操作,若其他地方也有类似操作,则建议提取为公共方法。

8.0

[^]、[...]数组切片

通常我们只能通过索引来获取数组的元素,通过Linq进行截取分割数组,如下

使用索引运算符,可以可以以更少的代码获取到我们想要的结果

^ 运算符指示序列末尾的元素位置,^1即倒数第一个、^2即倒数第2个、^e即倒数第e个,e可以是变量(可转int)也可以是数字、^length即第一个

.. 运算符指定某一索引范围的开头和末尾作为其操作数(左闭右开),可与 ^ 一起使用,.. 两边操作数均可省略。操作数为索引值,前数的索引必须要小于后数的索引。

  • a.. 等效于 a..^0
  • ..b 等效于 0..b
  • .. 等效于 0..^0
??、??= null合并操作符

?? 当左边值为null时,取右边值。左右值类型应该可以相互转换,或者右边值可以是异常表达式

如下,以下这两种写法都可以表示当name为null时,赋值空字符串给newName,不为null则将name赋值给newName

??= 和??类似,多了一层操作,若左边值为null它会将右边值赋值给左边值,再往下执行相关操作,我们往下看一下?、??、??=区别

! null包容运算符

这个唯一的作用就是在查阅代码时起到一个心理作用吧,如果这里使用了!,则表明该变量"不可能"为null,同时可以消除编辑器的null提示。

image-20230130163438076

但是如果值真为null,编译还是会报异常的。我个人感觉是没啥用的,但是好多人都在用...

image-20230130163645825

9.0

record

很少用,先不介绍吧

switch改动

c#8、c#9都致力于switch的更新,简单看一下吧,新的switch功能很强大但很少用,总是感觉用着不顺手。我们先看以往的switch,switch...case是一个萝卜一个坑进行匹配,若没找到对应的case就执行default分支了,这样一来除了刚好60、80、90、100的学生,其他学生不论多少分都是不及格的。程序这样处理肯定是不合理的,所以这里只能写成if...else...进行判断处理

最近版本switch也支持进行范围匹配了,我们看下如何处理。大家觉得这样的switch更清晰明了还是if...else...

init 访问器

字段属性原有get、set属性,新增init属性,意为初始化过后不可修改值,可读。

image-20230130170315052

顶级语句

除了新项目自动生成的Program.cs,项目中很少用。

  • 一个项目只能存在一个顶级文件
  • 顶级文件可以存在多个方法、类、命名空间,但他们都不能有访问修饰符
  • 顶级文件要依托于项目存在,单独的一个顶级文件是没有意义,是不能直接运行的(和python不一样)

image-20230130172322904

new 优化

当类型已知时,new初始化对象时可以不指定类型,如以下list初始化时,可以有"三种"写法

正常使用第二种写法就行了啊,而且也比第三种看着顺眼,为啥还要搞出第三种写法。如下我们可以看到,调用某方法时,类型已知,我们便可以简写为new()即可,不过这样用法还是很少

有一点值得肯定的是,创建数组时可以不用指定数组类型了,如果可以像js那样创建数组就更好了

10.0

namespace文件范围的命名空间

可以将namespace的大括号去掉,改为分号,这样一来一个文件就只能有一个namespace了,该文件内的成员都是该命名空间的成员。

image-20230130174849062

解除析构赋值的限制

解除析构赋值的限制,可先定义再重新赋值

const常量内插优化

之前const常量是无法进行加减乘除及字符串拼接的,目前支持了,这个挺好的

image-20230130181013159