C#基础回顾Async 的返回类型

博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈。

异步方法具有三个可能的返回类型:Task、Task 和 void。 

什么时候需要使用哪一种返回类型,具体情况需要具体分析。如果使用不当,程序的执行结果也许并不是你想要的,下面我们就来好好谈谈如何针对不同的情况选择不同的返回类型。

Task 

【记住】当你添加 async 关键字后,需要返回一个将用于后续操作的对象,请使用 Task。

Task 返回类型可用于某种异步方法,其中操作数含有类型 TResult。

在下面的示例中,GetDateTimeAsync 异步方法包含一个返回当前时间的 return 语句。 因此,方法声明必须指定 Task。

async Task GetDateTimeAsync(){    //Task.FromResult 是一个占位符,类型为 DateTime    return await Task.FromResult(DateTime.Now);}

调用 GetDateTimeAsync 方法:

async Task CallAsync(){    //在另一个异步方法的调用方式    DateTime now = await GetDateTimeAsync();}

当 GetDateTimeAsync 从 await 表达式中调用时,await 表达式将检索存储在由 GetDateTimeAsync 返回的任务中的 DateTime 类型值。 

async Task CallAsync(){    //在另一个异步方法的调用方式    //DateTime now = await GetDateTimeAsync();    //换种方式调用    Task t = GetDateTimeAsync();    DateTime now = await t;}

通过 CallAsync 方法对 GetDateTimeAsync 方法的调用,对非立即等待的方法 GetDateTimeAsync 的调用返回 Task。 该任务指派给示例中的 DateTime 的 Task 变量。 因为 DateTime 的 Task 变量是 Task,所以它属于包含类型 TResult 的 DateTime 属性。 在这种情况下,TResult 表示日期类型。 当 await 应用于 Task,await 表达式的计算结果为 Task 的 DateTime 属性内容。同时,该值会分配给 now 变量。

这次我演示不同的变量,你可以自己对比下结果是否相同:

async Task CallAsync(){    //在另一个异步方法的调用方式    DateTime now = await GetDateTimeAsync();    //换种方式调用    Task t = GetDateTimeAsync();    DateTime now2 = await t;   //输出的结果对比    Console.WriteLine($"now: {now}");    Console.WriteLine($"now2: {now2}");    Console.WriteLine($"t.Result: {t.Result}");}

【注意】Result 属性为锁定属性。 如果你在其任务完成之前尝试访问它,当前处于活动状态的线程将被阻止,直到任务完成且值为可用。 在大多数情况下,你应通过使用 await 访问属性值,而不是直接访问属性。

Task

不包含 return 语句或包含不返回操作数的 return 语句的异步方法通常具有返回类型 Task。 如果被编写为异步运行,这些方法将为返回 void 的方法。 如果在异步方法中使用 Task 返回类型,调用方法可以使用 await 运算符暂停调用方的完成,直至被调用的异步方法结束。

请看示例:

async Task DelayAsync(){    //Task.Delay 是一个占位符,用于假设方法正处于工作状态。    await Task.Delay(100);    Console.WriteLine("OK!");}

通过使用 await 语句而不是 await 表达式来调用和等待 DelayAsync 方法,类似于返回 void 的方法的调用语句。 await 运算符的应用程序在这种情况下不生成值。

请看调用 DelayAsync 的示例。

//调用和等待方法在同一声明中await DelayAsync();

现在,我用将调用和等待的方法进行分离:

//分离Task delayTask = DelayAsync();await delayTask;        void

void 返回类型主要用在事件处理程序中,其中需要 void 返回类型。 void 返回类型还可用于替代返回 void 的方法,或者用于执行可分类为”调用后不管了”活动的方法。 但是,你应尽可能地返回 Task,因为不能 await 返回 void 的异步方法。 这种方法的任何调用方只能够继续完成,而无需等待调用的异步方法完成,并且调用方必须独立于异步方法生成的任何值或异常。

返回 void 的异步方法的调用方无法捕获从该方法引发的异常,且此类未经处理的异常可能会导致应用程序故障。 如果返回 Task 或 Task 的异步方法中出现异常,此异常将存储于返回的任务中,并在等待该任务时再次引发。 因此,请确保可以产生异常的任何异步方法都具有返回类型 Task 或 Task,并确保会等待对这些方法的调用。

现在,异常也可以使用 await 了,请移步到这里 《回眸 C# 的前世今生 – 见证 C# 6.0 的新语法特性》。

void 返回值示例:

private async void button1_Click(object sender, EventArgs e){    //启动进程并等待完成    await Task.Delay(100);}

以上就是C#基础回顾Async 的返回类型的内容,更多相关内容请关注PHP中文网(www.php.cn)!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1432143.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 06:15:48
下一篇 2025年12月17日 06:16:02

相关推荐

  • C++怎样实现简易记账本 类封装与收支记录管理

    C++怎样实现简易记账本 类封装与收支记录管理C++怎样实现简易记账本 类封装与收支记录管理C++怎样实现简易记账本 类封装与收支记录管理C++怎样实现简易记账本 类封装与收支记录管理

    记账本适合用c++++练习类封装与数据管理,核心在于将收支记录抽象为类并合理组织代码结构。1. 设计incomeexpense类表示单条记录,包含金额、类型、日期、分类和备注,并提供访问和显示方法;2. ledger类管理所有记录,支持添加、显示全部、按分类筛选及统计总收入与支出;3. 主程序提供菜…

    2026年5月10日 用户投稿
    000
  • C++ 函数声明的演化:从 C++98 到 C++20 的语法变更

    随着 c++++ 标准演进,函数声明语法发生重大变化:从 c++98 到 c++11 引入了 auto 关键字,可自动推导返回值类型。c++14 增加了 constexpr 关键字,用于声明常量表达式函数。c++17 允许用 inline 关键字修饰声明,指示编译器内联函数。c++20 引入了协程,…

    2026年5月10日
    000
  • c++怎么将枚举(enum)转换为字符串_c++枚举转字符串实现方法

    C++中枚举无法自动转字符串,可通过std::map、switch语句、宏定义等方式实现映射,推荐switch高效清晰,宏适合大型项目维护。 在C++中,枚举(enum)不能直接转换为字符串,语言本身没有内置机制支持枚举值到字符串的自动转换。但可以通过几种常见方法实现枚举到字符串的映射,下面介绍几种…

    2026年5月10日
    000
  • C++内存管理中的引用计数机制

    引用计数机制在 c++++ 内存管理中用于跟踪对象的引用情况并自动释放未使用内存。该技术为每个对象维护一个引用计数器,当引用新增或移除时计数器相应增减。当计数器降为 0 时,对象被释放,无需手动管理。但循环引用会导致内存泄漏,且维护引用计数器会增加开销。 C++ 内存管理中的引用计数机制 在 C++…

    2026年5月10日
    000
  • C++ 函数重载在性能优化中的应用

    c++++ 函数重载可通过以下方式进行性能优化:1. 减少函数调用开销;2. 选择最佳函数实现;3. 防止不必要的类型转换。通过仔细设计重载函数,可提高应用程序的整体性能。 C++ 函数重载在性能优化中的应用 函数重载是 C++ 语言中的一项特性,它允许我们使用具有相同名称但不同签名(参数列表)的多…

    2026年5月10日
    000
  • c++中堆和栈的区别是什么_c++内存分配方式堆与栈的区别

    栈由编译器自动管理,适合小对象和临时变量,分配释放快;堆需手动管理,空间大但速度慢,适用于大或长期数据,使用不当易导致内存泄漏或碎片。 在C++中,堆和栈是两种不同的内存分配方式,它们在使用方式、生命周期、性能和管理责任上有明显区别。理解这些差异对编写高效、安全的程序至关重要。 1. 分配与释放方式…

    2026年5月10日
    200
  • C++ 框架如何支持人工智能模型的持续改进和维护?

    C++ 框架助力持续改进和维护 AI 模型 简介 训练和部署 AI 模型是一项持续的过程,需要不断改进和维护。C++ 框架提供了强大的工具和特性,以支持这些活动。 持续改进 立即学习“C++免费学习笔记(深入)”; 数据收集和特 征工 程 C++ 框架如 TensorFlow 和 PyTorch 提…

    2026年5月10日
    000
  • 内联函数在并行编程中的作用

    内联函数在并行编程中用于消除线程切换开销,从而提高性能。内联函数可通过将其调用替换为函数体代码来消除函数开销。语法:使用 inline 关键字声明内联函数。注意事项:过度内联函数会引起代码膨胀,导致编译时间增加和调试困难。 内联函数在并行编程中的应用 简介 内联函数是指编译器直接将函数调用替换为函数…

    2026年5月10日
    000
  • C++在资产管理系统中的数据建模

    c++++ 适用于资产管理系统的数据建模,因为它提供了对底层数据的精细控制。使用类和关系,可以表示资产实体和它们之间的关系。此外,c++ 的强大功能使它能够建立复杂且健壮的数据模型,以有效地存储和管理资产信息。 C++ 在资产管理系统中的数据建模 在资产管理系统中,数据模型是至关重要的,因为它决定了…

    2026年5月10日
    000
  • c++中static关键字在不同上下文中的作用 _c++ static关键字全方位解析

    static在C++中有多种用途:1. 在全局作用域中限制变量或函数的链接性,使其仅在当前编译单元内可见;2. 在类中定义静态成员变量,所有对象共享同一份数据,需在类外定义;3. 在类中定义静态成员函数,不依赖对象实例,无this指针,可直接通过类名调用。 在C++中,static关键字具有多种含义…

    2026年5月10日
    000
  • C++ 函数的艺术:定制容器与算法,掌控数据结构

    C++ 函数的艺术:定制容器与算法,掌控数据结构 引言 C++ 以其强大的自定义能力而闻名,允许程序员创建自己的数据结构和算法。通过使用函数模板,我们可以轻松定义满足我们特定需求的容器和算法。这篇文章将指导您了解如何使用函数模板来定制容器和算法,并提供实用案例以展示其功能。 定制容器 立即学习“C+…

    2026年5月10日
    300
  • 如何将C++框架与并行计算集成

    c++++框架与并行计算集成方法:使用并行库(如openmp);创建并行线程。实战案例:使用openmp加速数组求和,通过并行化for循环计算局部和再相加。集成并行计算可显著提升c++框架性能。 如何将C++框架与并行计算集成 在本文中,我们将探讨如何将C++框架与并行计算库集成,并提供使用真实案例…

    2026年5月10日
    000
  • c#怎么设置断点

    在 C# 中设置断点有四种方法:选择要暂停程序的行,使用快捷键(F9、Ctrl + F9、Shift + F9),通过菜单项,或在“调试”窗口中设置。设置断点后,可以在调试器中运行代码,当程序运行到断点时,它将暂停执行,并允许查看变量值或继续执行。 如何在 C# 中设置断点 断点是调试器中非常有用的…

    2026年5月10日
    000
  • c++中inline关键字的作用

    C++ 中 inline 关键字指示编译器在可能的情况下将函数内联。作用有:减少函数调用的开销,提高频繁调用的函数性能。改善代码可读性。提高编译时间。最佳实践:将频繁调用的小型函数标记为 inline。 C++ 中 inline 关键字的作用 inline 关键字用于修饰函数或成员函数,指示编译器在…

    2026年5月10日
    000
  • c++怎么使用条件变量condition_variable_c++条件变量同步机制详解

    条件变量需与互斥锁配合使用,实现线程同步。①包含头文件并定义std::condition_variable与std::mutex。②等待线程通过wait(lock, predicate)阻塞,避免虚假唤醒。③通知线程修改共享数据后调用notify_one()或notify_all()唤醒等待线程。④…

    2026年5月10日
    100
  • 如何在C++中实现单例模式?

    在c++++中实现单例模式可以通过静态成员变量和静态成员函数来确保类只有一个实例。具体步骤包括:1. 使用私有构造函数和删除拷贝构造函数及赋值操作符,防止外部直接实例化。2. 通过静态方法getinstance提供全局访问点,确保只创建一个实例。3. 为了线程安全,可以使用双重检查锁定模式。4. 使…

    2026年5月10日
    000
  • JS如何实现设计模式

    JavaScript通过其动态特性如闭包、原型继承和函数式编程,灵活实现设计模式以解决代码组织与维护问题。它不依赖接口或抽象类,而是利用对象组合与行为委托,形成独特的模式变体。例如,闭包实现单例,高阶函数支撑策略与观察者模式,Proxy让代理模式更强大。尽管ES6引入class语法,底层仍为原型继承…

    2026年5月10日
    000
  • C# CancellationTokenSource的用法 – 如何优雅地取消异步任务

    CancellationTokenSource 与 CancellationToken 配合实现协作式取消:前者发起取消请求,后者传递并监听信号,异步方法通过轮询或 ThrowIfCancellationRequested 响应,抛出 OperationCanceledException 终止执行。…

    2026年5月10日
    000
  • C++ 函数调用约定与栈帧管理:不同编译器的实现差异

    不同编译器实现函数调用约定和栈帧管理的方式差异显着:函数调用约定:c++decl:调用者清理栈帧。stdcall:被调用者清理栈帧。fastcall:第一个参数通过寄存器传递。不同编译器的默认实现:microsoft visual c++:__cdeclgcc 和 clang:__stdcallwa…

    2026年5月10日
    100
  • C# 如何使用Channel – .NET中高性能的生产者消费者队列

    Channel 是 .NET 5+ 推荐的异步生产者-消费者通信原语,相比 Queue 和 BlockingCollection 更轻量、支持无锁操作、内置完成与取消感知,具备有界/无界模式以控制背压,Reader/Writer 可分离实现组件解耦,配合 TryRead 批处理与 WriteAsyn…

    用户投稿 2026年5月10日
    000

发表回复

登录后才能评论
关注微信