此外,不能向不可为空引用类型分配一个可以为 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;} }
??

文章插图
接着,其实五个操作是分别开始执行的,那么当耗时短的任务处理好后 , 能否直接输出呢?这样的话交互体验就更好了!
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 宝藏好物 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
时,才能使用运算符 ??=
将其右操作数的值分配给左操作数 。
推荐阅读
- 在FreeSQL中实现「触发器」和软删除功能
- 小米12x和小米12pro区别-小米12x和小米12屏幕一样吗
- 华为手环6和华为fit哪个好_华为手环6和华为fit对比
- 小米civi和荣耀50pro区别对比_哪款更值得买
- 中国标准的青年和中年的年龄段分别是多少 中国青年年龄
- s20 fe 5g和s20区别_三星s20 fe 5g和三星s20区别
- 华为智慧屏s65和v65区别是什么_华为智慧屏s65和v65电视对比
- 微信怎样通过添加好友申请(微信发送添加好友申请)
- 用微信账号怎么添加好友(微信怎么查自己主动添加好友记录)
- 如何添加微信好友(微信加满5000好友技巧)