C# 8.0 添加和增强的功能【基础篇】( 四 )


??参考自:C# 8.0 宝藏好物 Async streams
九、异步可释放(IAsyncDisposable)IAsyncDisposable 接口,提供一种用于异步释放非托管资源的机制 。与之对应的就是提供同步释放非托管资源机制的接口 IDisposable
提供此类及时释放机制,可使用户执行资源密集型释放操作,从而无需长时间占用 GUI 应用程序的主线程 。
同时更好的完善.NET异步编程的体验,IAsyncDisposable诞生了 。它的用法与IDisposable非常的类似:
public class ExampleClass : IAsyncDisposable{ private Stream _memoryStream = new MemoryStream(); public ExampleClass() { } public async ValueTask DisposeAsync() {await _memoryStream.DisposeAsync(); }}// using 语法糖await using var s = new ExampleClass(){ // doing};// 优化 同样是对象 s 只存在于当前代码块await using var s = new ExampleClass();// doing??参考于:熟悉而陌生的新朋友——IAsyncDisposable
十、索引和范围索引和范围,为访问序列中的单个元素或范围,提供了简洁的语法 。
新增了两个类型(System.Index & System.Range)和运算符(末尾运算符"^" & 范围运算符“..”) 。
用例子说话吧:
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运算实例:
Console.WriteLine($"The last word is {words[^1]}");// “dog” // 使用 ^1 索引检索最后一个词var quickBrownFox = words[1..4];//“quick”、“brown”、“fox” 子范围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];十一、 Null 合并赋值Null 合并赋值运算符:??=
仅当左操作数计算为 null 时,才能使用运算符 ??= 将其右操作数的值分配给左操作数 。
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 开始,如果构造的值类型仅包含非托管类型的字段,则该类型不受管理 。
public struct Coords<T>{public T X;public T Y;}// Coords<int> 类型为 C# 8.0 及更高版本中的非托管类型// 与任何非托管类型一样,可以创建指向此类型的变量的指针,或针对此类型的实例在堆栈上分配内存块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 }};Span 简介
??在定义中,Span 就是一个简单的值类型 。它真正的价值,在于允许我们与任何类型的连续内存一起工作 。
??在使用中,Span 确保了内存和数据安全,而且几乎没有开销 。
??要使用 Span,需要设置开发语言为 C# 7.2 以上,并引用System.Memory到项目 。
??Span 使用时,最简单的,可以把它想象成一个数组,有一个Length属性和一个允许读写的index
// 常用的一些定义、属性和方法Span(T[] array);Span(T[] array, int startIndex);Span(T[] array, int startIndex, int length);unsafe Span(void* memory, int length);int Length { get; }ref T this[int index] { get; set; }Span<T> Slice(int start);Span<T> Slice(int start, int length);void Clear();void Fill(T value);void CopyTo(Span<T> destination);bool TryCopyTo(Span<T> destination);// 从 T[] 到 Span 的隐式转换char[] array = new char[] { 'i', 'm', 'p', 'l', 'i', 'c', 'i', 't' };Span<char> fromArray = array;// 复制内存int Parse(ReadOnlySpan<char> anyMemory);int Copy<T>(ReadOnlySpan<T> source, Span<T> destination);

经验总结扩展阅读