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

六、可处置的 ref 结构用 ref 修饰符声明的 struct 可能无法实现任何接口,也包括接口 IDisposable
class Program{static void Main(string[] args){using (var book = new Book())Console.WriteLine("Hello World!");}}// 错误写法// Error CS8343 'Book': ref structs cannot implement interfacesref struct Book : IDisposable{public void Dispose(){}}// 正确写法class Program{static void Main(string[] args){// 根据 using 新特性,简洁的写法,默认在当前代码块结束前销毁对象 bookusing var book = new Book();// ...}}ref struct Book{public void Dispose(){}}因此,若要能够处理 ref struct,就必须有一个可访问的 void Dispose() 方法 。
此功能同样适用于 readonly ref struct 声明 。
七、可为空引用类型若要指示一个变量可能为 null,必须在类型名称后面附加 ?,以将该变量声明为可为空引用类型 。否则都被视为不可为空引用类型 。
对于不可为空引用类型,编译器使用流分析来确保在声明时将本地变量初始化为非 Null 值 。字段必须在构造过程中初始化 。如果没有通过调用任何可用的构造函数或通过初始化表达式来设置变量,编译器将生成警告 。
此外,不能向不可为空引用类型分配一个可以为 Null 的值 。
编译器使用流分析,来确保可为空引用类型的任何变量,在被访问或分配给不可为空引用类型之前,都会对其 Null 性进行检查 。
八、异步流异步流,可针对流式处理数据源建模。数据流经常异步检索或生成元素,因此它们为异步流式处理数据源提供了自然编程模型 。
// 异步枚举,核心对象是:IAsyncEnumerable[HttpGet("syncsale")]public async IAsyncEnumerable<Product> GetOnSaleProducts(){var products = _repository.GetProducts();await foreach (var product in products) // 消费异步枚举,顺序取决于 IAsyncEnumerator 算法{if (product.IsOnSale)yield return product;// 持续异步逐个返回,不用等全部完成}}另一个实例:模拟异步抓取 html 数据
// 这是一个【相互独立的长耗时行为的集合(假设分别耗时 5,4,3,2,1s)】static async Task Main(string[] args){Console.WriteLine(DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\r\n");await foreach (var html in FetchAllHtml()) // 默认按照任务加入的顺序输出{Console.WriteLine(DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\t" + $"\toutput:{html}");}Console.WriteLine("\r\n" + DateTime.Now + $"\tThreadId:{Thread.CurrentThread.ManagedThreadId}\t");Console.ReadKey(); } // 这里已经默认实现了一个 IEnumerator 枚举器: 以 for 循环加入异步任务的顺序 static async IAsyncEnumerable<string> FetchAllHtml() {for (int i = 5; i >= 1; i--){var html = await Task.Delay(i* 1000).ContinueWith((t,i)=> $"html{i}",i); // 模拟长耗时yield return html;} }??

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

文章插图
接着,其实五个操作是分别开始执行的,那么当耗时短的任务处理好后,能否直接输出呢?这样的话交互体验就更好了!
static async IAsyncEnumerable<string> FetchAllHtml(){var tasklist= new List<Task<string>>();for (int i = 5; i >= 1; i--){var t= Task.Delay(i* 1000).ContinueWith((t,i)=>$"html{i}",i);// 模拟长耗时任务tasklist.Add(t);}while(tasklist.Any())// 监控已完成的操作,立即处理{var tFinlish = await Task.WhenAny(tasklist);tasklist.Remove(tFinlish);yield return await tFinlish; // 完成即输出}}以上总耗时取决于 耗时最长的那个异步任务5s 。
??
C# 8.0 添加和增强的功能【基础篇】

文章插图

经验总结扩展阅读