零度 C#7.0 中的语言新特性

2023/7/6 02:13:37

"零度 C#7.0 中的语言新特性 在去年,零度分享了 C#6.0 中的新特性,随着时间的推移,微软发布了 Visual Studio 2017,同时 C#7.0 发布已经有一段时间了,C#7.0 中新增了非常有用的新功能,如果您是.NET开发者,建议花些时间来了解这些新特性。

1、Out 变量

在之前版本的 C# 中,使用 out 变量,您需要先定义并申明变量,如下所示。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> value; <span style=color: rgb(0, 128, 0);>//需要预先定义 <span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>if<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>.TryParse(<span style=color: rgb(163, 21, 21);>123<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> value)) { <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(value); } }

在 C#7.0 中,可以在传参的同时进行申明,当然也可以将 int 改成 var 匿名类型。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>if<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>.TryParse(<span style=color: rgb(163, 21, 21);>123<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> value)) { <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(value); } }

2、元组特性

当编写一个函数时,有时需要返回多个结果,而且这个结果只用一次,不必创建对象,用元组就可返回多个结果,首选需要安装 System.ValueTuple 这个库。

<span style=color: rgb(0, 0, 0);>install-package System.ValueTuple

通过下面的方法,就可使用元组返回多个值。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> v1, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> v2, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> v3) GetValues() { <span style=color: rgb(0, 0, 255);>return<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(163, 21, 21);>零度<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(163, 21, 21);>编程<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(163, 21, 21);>官网<span style=color: rgb(0, 0, 0);>); }

也可以只给定类型不设置参数名来定义返回元组的方法。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>) GetValues() { <span style=color: rgb(0, 0, 255);>return<span style=color: rgb(0, 0, 0);> (<span style=color: rgb(163, 21, 21);>零度<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(163, 21, 21);>编程<span style=color: rgb(0, 0, 0);>, <span style=color: rgb(163, 21, 21);>官网<span style=color: rgb(0, 0, 0);>); }

可以通过以下的方式来调用元组方法。

<span style=color: rgb(0, 0, 0);>(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> a, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> b, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> c) = GetValues(); <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(a + b + c);

也可直接使用 var 匿名类型来接收元组方法的返回值,与以上调用方式等效。

<span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> result = GetValues(); <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(result.v1 + result.v2 + result.v3);

3、解析方法

解析方法可以将方法返回的元组进行解析,解析方法很灵活,可以通过以下几种解析方法解析元祖。

<span style=color: rgb(0, 0, 0);>(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> first, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> middle, <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> last) = GetValues(); <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(first + middle + last);

在内部使用 var 匿名类型的解析方法。

<span style=color: rgb(0, 0, 0);>(<span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> first, <span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> middle, <span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> last) = GetValues();

甚至可以将 var 放在括号外进行简写。

<span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> (first, middle, last) = GetValues();

当然,解析方法不仅仅适用于元组,如要它拥有如下的形式,就能够使用解析方法。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Deconstruct(<span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> T1 x1, ..., <span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> Tn xn)

为类定义一个解析方法(也可以是扩展方法),需要符合如上的 Deconstruct 格式,如下所示。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>class<span style=color: rgb(0, 0, 0);> <span style=color: rgb(43, 145, 175);>Book <span style=color: rgb(0, 0, 0);>{ <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> BookID { <span style=color: rgb(0, 0, 255);>get<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 0, 255);>set<span style=color: rgb(0, 0, 0);>; } <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>double<span style=color: rgb(0, 0, 0);> BookPrice { <span style=color: rgb(0, 0, 255);>get<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 0, 255);>set<span style=color: rgb(0, 0, 0);>; } <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Deconstruct(<span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> id, <span style=color: rgb(0, 0, 255);>out<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>double<span style=color: rgb(0, 0, 0);> price) }

在外部可以使用如下的方式调用一个类的解析方法,系统会自动推断出 book 对象 Deconstruct 方法并解析。

<span style=color: rgb(43, 145, 175);>Book<span style=color: rgb(0, 0, 0);> book = <span style=color: rgb(0, 0, 255);>new<span style=color: rgb(0, 0, 0);> <span style=color: rgb(43, 145, 175);>Book<span style=color: rgb(0, 0, 0);> ; (<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> id, <span style=color: rgb(0, 0, 255);>double<span style=color: rgb(0, 0, 0);> price) = book; <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(price);

4、模式匹配

之前,我们判断一个对象是否兼容某个类型,一般使用 is 关键字,兼容则进行隐式类型转换,然后参与运算,代码如下。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>object<span style=color: rgb(0, 0, 0);> objectValue = 123; <span style=color: rgb(0, 0, 255);>if<span style=color: rgb(0, 0, 0);> (objectValue <span style=color: rgb(0, 0, 255);>is<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>) { <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> intValue = (<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>)objectValue; <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> sum = intValue + 321; <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(sum); } }

现在,我们可以使用模式匹配特性将类型判断与转换同时进行。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>object<span style=color: rgb(0, 0, 0);> objectValue = 123; <span style=color: rgb(0, 0, 255);>if<span style=color: rgb(0, 0, 0);> (objectValue <span style=color: rgb(0, 0, 255);>is<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> intValue) { <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> sum = intValue + 321; <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(sum); } }

当然,除了 if 语句进行模式匹配外,switch 语句也支持模式匹配。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>dynamic<span style=color: rgb(0, 0, 0);> AddValue(<span style=color: rgb(0, 0, 255);>object<span style=color: rgb(0, 0, 0);> value) { <span style=color: rgb(0, 0, 255);>dynamic<span style=color: rgb(0, 0, 0);> result=<span style=color: rgb(0, 0, 255);>null<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 0, 255);>switch<span style=color: rgb(0, 0, 0);> (value) { <span style=color: rgb(0, 0, 255);>case<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> b: result = b++; <span style=color: rgb(0, 0, 255);>break<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 0, 255);>case<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> c: result = c + <span style=color: rgb(163, 21, 21);>零度<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 0, 255);>break<span style=color: rgb(0, 0, 0);>; } <span style=color: rgb(0, 0, 255);>return<span style=color: rgb(0, 0, 0);> result; }

5、局部函数

在 C#7 中可以在函数内部定义函数并调用,下面的代码在 Main 函数中定义一个 Add 函数,然后调用这个函数。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> Add(<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> value1, <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> value2) { <span style=color: rgb(0, 0, 255);>return<span style=color: rgb(0, 0, 0);> value1 + value2; } <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> result = Add(111, 222); <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(result); }

6、数值文字

为了提高数值类型的可读性,C#7 中引入数值可读性,使用此特性,在不影响最终结果的情况下,通过下划线提高数值的可读性。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) {<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> intValue = 123_456_000_000; <span style=color: rgb(0, 128, 0);>//表示123456000000
<span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> hexValue = 0xAB_CD_EF; <span style=color: rgb(0, 128, 0);>//0x表示十六进制 <span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>var<span style=color: rgb(0, 0, 0);> binValue = 0b1010_1011_1100_1101_1110_1111; <span style=color: rgb(0, 128, 0);>//0b表示二进制 <span style=color: rgb(0, 0, 0);>}

既然是数值类型的分割,那么同样可用于 decimal、float 和 double 类型。

7、方法主体使用表达式

在 C#6 中定义函数时,可以将一个 Lambda 表达式作为函数主体,在 C#7 中表达式可以用在访问器、构造器和析构器。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>class<span style=color: rgb(0, 0, 0);> <span style=color: rgb(43, 145, 175);>Person <span style=color: rgb(0, 0, 0);>{ <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> PrintName() => <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(firstName); <span style=color: rgb(0, 0, 255);>private<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> firstName = <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>.Empty; <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> Person(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> name) => firstName=name; <span style=color: rgb(0, 128, 0);>//构造函数 <span style=color: rgb(0, 0, 0);> ~Person() => firstName=<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>.Empty; <span style=color: rgb(0, 128, 0);>//析构函数 <span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> FirstName { <span style=color: rgb(0, 0, 255);>get<span style=color: rgb(0, 0, 0);> => firstName; <span style=color: rgb(0, 128, 0);>//GET访问器 <span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>set<span style=color: rgb(0, 0, 0);> => firstName = <span style=color: rgb(0, 0, 255);>value<span style=color: rgb(0, 0, 0);>; <span style=color: rgb(0, 128, 0);>//SET访问器 <span style=color: rgb(0, 0, 0);> } }

8、异常表达式

之前,通过条件判断抛出指定的异常。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> WriteString(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> parameter) { <span style=color: rgb(0, 0, 255);>if<span style=color: rgb(0, 0, 0);> (parameter == <span style=color: rgb(0, 0, 255);>null<span style=color: rgb(0, 0, 0);>) { <span style=color: rgb(0, 0, 255);>throw<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>new<span style=color: rgb(0, 0, 0);> <span style=color: rgb(43, 145, 175);>ArgumentNullException<span style=color: rgb(0, 0, 0);>(); } <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(parameter); }

现在,可以将异常抛出作为表达式来使用。

<span style=color: rgb(0, 0, 255);>public<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> WriteString2(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);> parameter) { parameter = parameter?? <span style=color: rgb(0, 0, 255);>throw<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>new<span style=color: rgb(0, 0, 0);> <span style=color: rgb(43, 145, 175);>ArgumentNullException<span style=color: rgb(0, 0, 0);>(); <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(parameter); }

9、将 ref 用于变量和返回值

之前,ref 关键字可将值类型通过引用进行传递,现在 ref 可以用于局部变量和返回值,以下代码将变量 x 的引用传递给 y 变量,也就是说 y 与 x 引用相同的内存地址,下面的代码输出 x 的值为 2。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>void<span style=color: rgb(0, 0, 0);> Main(<span style=color: rgb(0, 0, 255);>string<span style=color: rgb(0, 0, 0);>[] args) { <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> x = 3; <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> y = <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> x; y = 2; <span style=color: rgb(43, 145, 175);>Console<span style=color: rgb(0, 0, 0);>.WriteLine(x); <span style=color: rgb(0, 128, 0);> <span style=color: rgb(0, 0, 0);>}

在方法返回值中使用 ref 引用变量。

<span style=color: rgb(0, 0, 255);>static<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> GetValue(<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>[] array, <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> index) => <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> array[index];

以上函数可以使用如下的方式进行调用。

<span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);>[] array = { 1, 2, 3, 4, 5 }; <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> <span style=color: rgb(0, 0, 255);>int<span style=color: rgb(0, 0, 0);> x = <span style=color: rgb(0, 0, 255);>ref<span style=color: rgb(0, 0, 0);> GetValue(array, 2);"