windows C#-异步返回类型(下)

ops/2024/11/23 5:28:06/
Void 返回类型

在异步事件处理程序中使用 void 返回类型,这需要 void 返回类型。 对于事件处理程序以外的不返回值的方法,应返回 Task,因为无法等待返回 void 的异步方法。 此类方法的任何调用方都必须继续完成,而无需等待调用的异步方法完成。 调用方必须独立于异步方法生成的任何值或异常。

Void 返回异步方法的调用方无法捕获从该方法引发的异常。 此类未经处理异常有可能导致应用程序失败。 如果返回 Task 或 Task<TResult> 的方法引发异常,则该异常存储在返回的任务中。 等待任务时,将重新引发异常。 请确保可以产生异常的任何异步方法都具有返回类型 Task 或 Task<TResult>,并确保会等待对方法的调用。

以下示例演示异步事件处理程序的行为。 在本示例代码中,异步事件处理程序必须在完成时通知主线程。 然后,主线程可在退出程序之前等待异步事件处理程序完成。

public class NaiveButton
{public event EventHandler? Clicked;public void Click(){Console.WriteLine("Somebody has clicked a button. Let's raise the event...");Clicked?.Invoke(this, EventArgs.Empty);Console.WriteLine("All listeners are notified.");}
}public class AsyncVoidExample
{static readonly TaskCompletionSource<bool> s_tcs = new TaskCompletionSource<bool>();public static async Task MultipleEventHandlersAsync(){Task<bool> secondHandlerFinished = s_tcs.Task;var button = new NaiveButton();button.Clicked += OnButtonClicked1;button.Clicked += OnButtonClicked2Async;button.Clicked += OnButtonClicked3;Console.WriteLine("Before button.Click() is called...");button.Click();Console.WriteLine("After button.Click() is called...");await secondHandlerFinished;}private static void OnButtonClicked1(object? sender, EventArgs e){Console.WriteLine("   Handler 1 is starting...");Task.Delay(100).Wait();Console.WriteLine("   Handler 1 is done.");}private static async void OnButtonClicked2Async(object? sender, EventArgs e){Console.WriteLine("   Handler 2 is starting...");Task.Delay(100).Wait();Console.WriteLine("   Handler 2 is about to go async...");await Task.Delay(500);Console.WriteLine("   Handler 2 is done.");s_tcs.SetResult(true);}private static void OnButtonClicked3(object? sender, EventArgs e){Console.WriteLine("   Handler 3 is starting...");Task.Delay(100).Wait();Console.WriteLine("   Handler 3 is done.");}
}
// Example output:
//
// Before button.Click() is called...
// Somebody has clicked a button. Let's raise the event...
//    Handler 1 is starting...
//    Handler 1 is done.
//    Handler 2 is starting...
//    Handler 2 is about to go async...
//    Handler 3 is starting...
//    Handler 3 is done.
// All listeners are notified.
// After button.Click() is called...
//    Handler 2 is done.
通用的异步返回类型和 ValueTask<TResult>

异步方法可以返回具有返回 awaiter 类型实例的可访问 GetAwaiter 方法的所有类型。 此外,GetAwaiter 方法返回的类型必须具有 System.Runtime.CompilerServices.AsyncMethodBuilderAttribute 特性。

此功能与 awaitable 表达式相辅相成,后者描述 await 操作数的要求。 编译器可以使用通用异步返回类型生成返回不同类型的 async 方法。 通用异步返回类型通过 .NET 库实现性能改进。 Task 和 Task<TResult> 是引用类型,因此,性能关键路径中的内存分配会对性能产生负面影响,尤其当分配出现在紧凑循环中时。 支持通用返回类型意味着可返回轻量值类型(而不是引用类型),从而避免额外的内存分配。

.NET 提供 System.Threading.Tasks.ValueTask<TResult> 结构作为返回任务的通用值的轻量实现。 如下示例使用 ValueTask<TResult> 结构检索两个骰子的值。

class Program
{static readonly Random s_rnd = new Random();static async Task Main() =>Console.WriteLine($"You rolled {await GetDiceRollAsync()}");static async ValueTask<int> GetDiceRollAsync(){Console.WriteLine("Shaking dice...");int roll1 = await RollAsync();int roll2 = await RollAsync();return roll1 + roll2;}static async ValueTask<int> RollAsync(){await Task.Delay(500);int diceRoll = s_rnd.Next(1, 7);return diceRoll;}
}
// Example output:
//    Shaking dice...
//    You rolled 8

编写通用异步返回类型是一种高级方案,旨在用于专门的环境。 请考虑改用 Task、Task<T> 和 ValueTask<T> 类型,它们适用于大多数的异步代码方案。

在 C# 10 及更高版本中,可以将 AsyncMethodBuilder 属性应用于异步方法(而不是异步返回类型声明),用于替代该类型的生成器。 通常会应用此属性来利用 .NET 运行时中提供的另一种生成器。

使用 IAsyncEnumerable<T> 的异步流

异步方法可能返回异步流,由 IAsyncEnumerable<T> 表示。 异步流提供了一种方法,来枚举在具有重复异步调用的块中生成元素时从流中读取的项。 以下示例显示生成异步流的异步方法:

static async IAsyncEnumerable<string> ReadWordsFromStreamAsync()
{string data =@"This is a line of text.Here is the second line of text.And there is one more for good measure.Wait, that was the penultimate line.";using var readStream = new StringReader(data);string? line = await readStream.ReadLineAsync();while (line != null){foreach (string word in line.Split(' ', StringSplitOptions.RemoveEmptyEntries)){yield return word;}line = await readStream.ReadLineAsync();}
}

前面的示例异步读取字符串中的行。 读取每一行后,代码将枚举字符串中的每个单词。 调用方将使用 await foreach 语句枚举每个单词。 当需要从源字符串异步读取下一行时,该方法将等待。 


http://www.ppmy.cn/ops/135991.html

相关文章

Softing工业将OPC UA信息建模集成到边缘应用和安全集成服务器中

Softing工业宣布将OPC UA&#xff08;统一架构&#xff09;信息建模集成到其边缘产品系列及安全集成服务器&#xff08;SIS&#xff09;中&#xff0c;这一技术进步使得在工业物联网&#xff08;IIoT&#xff09;应用中的数据集成、交换与控制更加无缝、有效。 &#xff08;OPC…

没钱买KEGG怎么办?REACTOME开源通路更强大

之前搜集免费生物AI插图时简单提到了通路数据库Reactome&#xff08;https://reactome.org/&#xff09;&#xff0c; 那些精美的生物插图只能算是该数据库附赠的小礼品&#xff0c;他的主要功能还是作为一个开源的通路数据库&#xff0c;为相关领域的研究者提供直观的可视化生…

vue项目中富文本编辑器的实现

文章目录 vue前端实现富文本编辑器的功能需要用到第三方库1. 安装包2.全局引入注册3.组件内使用4.图片缩放功能实现①安装包②注册并添加配置项③报错解决 vue前端实现富文本编辑器的功能需要用到第三方库 vue2使用vue-quill-editor&#xff0c;vue3使用vueup/vue-quill&#…

linux003.在ubuntu中安装cmake的方法

1.cmake安装程序下载 https://cmake.org/files/v3.30/ 2.解压并下载包 解压cmake压缩包 tar -xvzf cmake.tar.gz进入解压目录 cd cmake-<version>编辑~/.bashrc nano ~/.bashrc在文件的末尾添加如下代码 export PATH/home/xwl/software/cmake/bin:$PATH然后运行以…

C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)

最近在做一个与激光器用串口进行通讯的程序文档中要求将频率参数以3个字节的方式进行发送。这里记录一下过程。以便以后再有类似问题时可以快速解决。 /// <summary>/// 设置频率/// </summary>/// <param name"sender"></param>/// <par…

自动化立体仓库:详解

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 自动化立体仓库&#xff08;Automated S…

科研实验室的数字化转型:Spring Boot系统

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理实验室管理系统的相关信息成为必然。开发合…

litepal proguardFiles android studio

Step1&#xff1a;settings.gradle.kts or settings.gradle 添加阿里源 dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {maven(url "https://jitpack.io")maven (url "https://maven.aliyu…