C#8.0特性(二)

接上回c# 8.0特性介绍, 这回我们开始介绍最新的C# 新特性,需要了解7.0特性以及上一篇文章的请点击下面的链接

当然放上目录:

Readonly 成员默认接口方法模式匹配增强功能Using申明静态本地函数可处置的ref结构可为空的引用类型异步流索引和范围Null合并赋值非托管构造类型嵌套表达式中的Stackalloc内插逐字字符串的增强功能平台支持情况

静态本地函数

在上次介绍c# 7.0增强特性中提到可以添加本地函数来增强代码的模块化以及可读性,这次再来看看在c# 8.0中上次提到的本地函数可以进一步被申明为静态的,即在本地函数前面加上 static 关键字,由于加上static后,本地函数变成静态的,所以可以确保本地函数不引用或使用封闭范围内的任何变量。示例:

<code>int Demo()
{
int y = 5;
int x = 7;
return Add(x, y);

static int Add(Int32 left, Int32 right) => left + right;
}/<code>

Disposable ref structs

ref struct 这样声明的结构无法实现额外的接口,因此无法实现IDisposable这个接口,但是可以通过提供一个可以访问的void Dispose()方法,来实现Dispose的功能; readonly ref struct 这样的结构也是可以的

可为空引用类型

在可为空注释上下文中,引用类型的任何变量都被视为不可为空引用类型 。 若要指示一个变量可能为 null,必须在类型名称后面附加 ?,以将该变量声明为可为空引用类型 。

任何引用类型都可以具有四个“为 Null 性”中的一个,它描述了何时生成警告 :

不可为空:无法将 null 分配给此类型的变量。 在取消引用之前,无需对此类型的变量进行 null 检查。可为空:可将 null 分配给此类型的变量。 在不首先检查 null 的情况下取消引用此类型的变量时发出警告。无视:这是 C# 8.0 之前版本的状态。 可以取消引用或分配此类型的变量而不发出警告。未知:这通常针对类型参数,约束不告知编译器类型是否必须是“可为空”或“不可为空” 。

在C#8.0 以前的版本。默认被认为是不启用的,在之后的版本中用 .csproj 文件中的 Nullable 元素为项目设置可为空注释上下文和可为空警告上下文

<code>// .csproj 文件中的配置是全局的
<nullable>enable/<nullable>
<nullable>warnings/<nullable>
<nullable>annotations/<nullable>
<nullable>disable/<nullable>
// 使用指令来局部指定 示例如下
#nullable enable 将可为空注释上下文和可为空警告上下文设置为“已启用” 。


#nullable disable warnings 将可为空警告上下文设置为“已禁用” 。/<code>

异步流

从 C# 8.0 开始,可以创建并以异步方式使用流。 返回异步流的方法有三个属性:

它是用 async 修饰符声明的。它将返回 IAsyncEnumerable。该方法包含用于在异步流中返回连续元素的 yield return 语句。

使用异步流需要在枚举流元素时在 foreach 关键字前面添加 await 关键字。

<code>await foreach (var number in GenerateSequence())
{
Console.WriteLine(number);
}/<code>

索引和范围

索引和范围为访问序列中的单个元素或范围提供了简洁的语法。此特性依赖于两个新类型以及两个新运算符

System.Index 表示一个序列索引。来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关。System.Range 表示序列的子范围。范围运算符 ..,用于指定范围的开始和末尾,就像操作数一样。

<code>// A string array contains some string
var words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2


"dog" // 8 ^1
}; // 9 (or words.Length) ^0
Console.WriteLine($"The last word is {words[^1]}"); // writes "dog"
var quickBrownFox = words[1..4]; // 包含 quick brown fox 不包含 jumped
var lazyDog = words[^2..^0]; // 包含 lazy dog
var allWords = words[..]; // 包含 "The" 到 "dog"的所有元素
var firstPhrase = words[..4]; // 包含 "The" 到 "fox"
var lastPhrase = words[6..]; // 包含 "the", "lazy", "dog"
Range phrase = 1..4; // 通过此来声明一个范围
var text = words[phrase]; // 在中括号中使用刚刚声明的phrase/<code>

Null 合并赋值

新的运算符被 ??= 定义,仅当左操作数计算为 null 时,才能使用运算符 ??= 将其右操作数的值分配给左操作数。

<code>List numbers = null;
int? i = null;

numbers ??= new List();
numbers.Add(i ??= 17);/<code>

非托管构造类型

在 C# 7.3 及更低版本中,构造类型(包含至少一个类型参数的类型)不能为非托管类型。 从 C# 8.0 开始,如果构造的值类型仅包含非托管类型的字段,则该类型不受管理。

<code>public struct Coords
{
public T X;
public T Y;
}
// Coords 类型为 C# 8.0 及更高版本中
// 的非托管类型。 与任何非托管类型一样,可
// 以创建指向此类型的变量的指针,或针对此类


// 型的实例在堆栈上分配内存块:
Span<coords>> coordinates = stackalloc[]
{
new Coords { X = 0, Y = 0 },
new Coords { X = 0, Y = 3 },
new Coords { X = 4, Y = 0 }
};/<coords>/<code>

嵌套表达式中的 stackalloc

如果 stackalloc 表达式的结果为 System.Span 或 System.ReadOnlySpan 类型,则可以在其他表达式中使用 stackalloc 表达式

<code>Span numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6 ,8 });
Console.WriteLine(ind); // output: 1/<code>

内插逐字字符串的增强功能

内插逐字字符串中 $ 和 @ 标记的顺序可以任意安排:$@"..." 和 @$"..." 均为有效的内插逐字字符串。 在早期 C# 版本中,$ 标记必须出现在 @ 标记之前。

<code>// in previous versions of c#
var filePath = $@"c:\\demoDir\\{testDir}\\demo.txt";
// in c# 8.0 but also type as bellow
var filePath = @$"c:\\demoDir\\{testDir}\\demo.txt";/<code>

好了,本次的主要内容就到这里了后面的内容是关于各个.Net平台的支持情况

目标框架 version C# 语言版本的默认值

.NET Core 3.x C# 8.0

.NET Core 2.x C# 7.3

.NET Standard 2.1 C# 8.0

.NET Standard 2.0 C# 7.3

.NET Standard 1.x C# 7.3

.NET Framework all C# 7.3