C# 8.0 中的新增功能( 四 )

可以在创建和使用异步流的教程中自行尝试异步流 。默认情况下,在捕获的上下文中处理流元素 。如果要禁用上下文捕获,请使用 TaskAsyncEnumerableExtensions.ConfigureAwait 扩展方法 。有关同步上下文并捕获当前上下文的详细信息,请参阅有关使用基于任务的异步模式的文章 。
异步可释放从 C# 8.0 开始,语言支持实现 System.IAsyncDisposable 接口的异步可释放类型 。可使用 await using 语句来处理异步可释放对象 。有关详细信息,请参阅实现 DisposeAsync 方法 。
索引和范围索引和范围为访问序列中的单个元素或范围提供了简洁的语法 。
此语言支持依赖于两个新类型和两个新运算符:

  • System.Index 表示一个序列索引 。
  • 来自末尾运算符 ^ 的索引,指定一个索引与序列末尾相关 。
  • System.Range 表示序列的子范围 。
  • 范围运算符 ..,用于指定范围的开始和末尾,就像操作数一样 。
让我们从索引规则开始 。请考虑数组 sequence 。0 索引与 sequence[0] 相同 。^0 索引与 sequence[sequence.Length] 相同 。请注意,sequence[^0] 不会引发异常,就像 sequence[sequence.Length] 一样 。对于任何数字 n,索引 ^n 与 sequence.Length - n 相同 。
范围指定范围的开始和末尾。包括此范围的开始,但不包括此范围的末尾,这表示此范围包含开始但不包含末尾。范围 [0..^0] 表示整个范围,就像 [0..sequence.Length] 表示整个范围 。
请看以下几个示例 。请考虑以下数组,用其顺数索引和倒数索引进行注释:
C#
var words = new string[]{// index from startindex 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可以使用 ^1 索引检索最后一个词:
C#
Console.WriteLine($"The last word is {words[^1]}");// writes "dog"以下代码创建了一个包含单词“quick”、“brown”和“fox”的子范围 。它包括 words[1] 到 words[3] 。元素 words[4] 不在该范围内 。
C#
var quickBrownFox = words[1..4];以下代码使用“lazy”和“dog”创建一个子范围 。它包括 words[^2] 和 words[^1] 。末尾索引 words[^0] 不包括在内:
C#
var lazyDog = words[^2..^0];下面的示例为开始和/或结束创建了开放范围:
C#
var allWords = words[..]; // contains "The" through "dog".var firstPhrase = words[..4]; // contains "The" through "fox"var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"此外可以将范围声明为变量:
C#
Range phrase = 1..4;然后可以在 [ 和 ] 字符中使用该范围:
C#
var text = words[phrase];不仅数组支持索引和范围 。还可以将索引和范围用于 string、Span<T> 或 ReadOnlySpan<T> 。有关详细信息,请参阅索引和范围的类型支持 。
可在有关索引和范围的教程中详细了解索引和范围 。
Null 合并赋值C# 8.0 引入了 null 合并赋值运算符 ??= 。仅当左操作数计算为 null 时,才能使用运算符 ??= 将其右操作数的值分配给左操作数 。
C#
List<int> numbers = null;int? i = null;numbers ??= new List<int>();numbers.Add(i ??= 17);numbers.Add(i ??= 20);Console.WriteLine(string.Join(" ", numbers));// output: 17 17Console.WriteLine(i);// output: 17有关详细信息,请参阅 ?? 和 ??= 运算符一文 。
非托管构造类型在 C# 7.3 及更低版本中,构造类型(包含至少一个类型参数的类型)不能为非托管类型 。从 C# 8.0 开始,如果构造的值类型仅包含非托管类型的字段,则该类型不受管理 。
例如,假设泛型 Coords<T> 类型有以下定义:
C#
public struct Coords<T>{public T X;public T Y;}Coords<int> 类型为 C# 8.0 及更高版本中的非托管类型 。与任何非托管类型一样,可以创建指向此类型的变量的指针,或针对此类型的实例在堆栈上分配内存块:
C#
Span<Coords<int>> coordinates = stackalloc[]{new Coords<int> { X = 0, Y = 0 },new Coords<int> { X = 0, Y = 3 },new Coords<int> { X = 4, Y = 0 }};有关详细信息,请参阅非托管类型 。
嵌套表达式中的 stackalloc从 C# 8.0 开始,如果 stackalloc 表达式的结果为 System.Span<T> 或 System.ReadOnlySpan<T> 类型,则可以在其他表达式中使用 stackalloc 表达式:


推荐阅读