C# 中异步方法返回类型概述

发布日期:2026-07-14 19:19:05   来源 : 杭州电子商务研究院    浏览量 :9
杭州电子商务研究院 发布日期:2026-07-14 19:19:05  
9

介绍

在 C# 中使用async/await时,您可能会遇到一些编译器警告和错误,尤其是与返回类型相关的警告和错误。事实证明,标记为async的方法的调用者的要求因方法的返回类型而异。更重要的是,更改异步方法的返回类型可能会具有传染性,在某些情况下,您不仅需要更改其调用者的签名,还需要更改其调用者的调用者的签名等等。虽然这最初可能被视为一种烦恼,但它实际上是一个重要的主题,因为返回类型会影响代码的执行顺序。

异步方法返回类型一览

C#中标有async 的方法必须返回下列之一:

  • 任务
  • 任务<T>
  • 价值任务
  • 值任务<T>
  • 空白

这不是一份完整的列表。虽然如何执行此操作的详细信息超出了本指南的范围,但值得注意的是,从 C# 7.0 开始,您还可以定义自己的类似任务的类型。不过,这是一个不常见的要求。

要清楚的是,当我们说返回类型时,我们指的是方法签名中方法名称之前的内容。例如:

      public static async Task MyMethod(int myParameter)
{
  ...
}
    

在上述方法签名中,publicstaticasync都被称为“修饰符”。C# 编译器不会强制执行这些修饰符的顺序,但通常,作为惯例,async修饰符放在最后,就在返回类型(本例中为Task)之前。正是由于这种典型的定位,C# 中的异步方法通常被称为async voidasync Task。这两者之间的对比很重要,我们接下来会看到。

为什么你应该坚持完成任务

如果您对上面的返回类型列表感到不知所措,请让我让您放心。大多数情况下,您应该只使用具有异步方法的返回类型TaskTask<T>上面列表中的所有其他内容都适用于不太常见的特定情况。

无论如何,您可以选择返回Task或返回void。但即使是这种选择也是不平衡的,严重偏向于使用Task。为什么?如果方法返回void,则不允许该方法的调用者等待它。如果您不等待方法,则调用者的执行可能会在方法完成之前继续。更成问题的是,当调用者不等待异步方法时,它无法正确处理异常。从异步方法返回void有几个有效的原因,但绝大多数时候您应该返回Task以便您可以等待它。

何时使用任务,何时使用任务

如果在Taskvoid之间进行选择很容易,那么在TaskTask<T>之间进行选择就更容易了。当您需要从方法中返回某些信息时,请使用Task<T> ,当不需要时,请使用Task 。

Task <T>类具有类型为TResult属性,其中包含您在方法中使用return语句传回的任何内容。调用者通常通过使用await隐式检索存储在Result属性中的内容。例如,以下GetHtml方法将返回从远程服务器检索到的 html 字符串,如果未指定url ,则返回 null 。

      async Task<string> GetHtml(string url)
{
  if (string.IsNullOrEmpty(url))
  {
    return null;
  }  
  string html = await new HttpClient().GetStringAsync(url);
  return html;
}
    

可以通过明确引用 Result 属性来访问上述方法返回的 html:

      Task<string> myTask = client.GetHtml("http://...");
await myTask;
string html = myTask.Result;
    

但通常情况下,通过await隐式地​​内联访问它会更容易、更易读

      string html = await GetHtml("http://...");
    

需要明确的是,使用普通的Task时,不能从异步方法返回任何内容。例如,这将无法编译:

      async Task GetHtml(string url)
{
  return await new HttpClient().GetStringAsync(url);
}
    

...但是这

      async Task<string> GetHtml(string url)
{
  return await new HttpClient().GetStringAsync(url);
}
    

另一种思考方式是,在异步方法中选择TaskTask<T>类似于在同步方法中选择void和任何其他类型。例如,以下同步方法:

      void DoOperation()
{
  SomeOperation();
}

byte[] GetData()
{
  return GetData("/path/to/data");
}
    

...当与Task.Run “异步” 时,将变成:

      async Task DoOperation()
{
  await Task.Run(SomeOperation);
}

async Task<byte[]> GetData()
{
  return await Task.Run(() => GetData("/path/to/data"));
}
    

异步方法中允许的参数类型

需要将Task<T>传回数据给调用者的原因之一是异步方法不允许有refout参数。

C# 7.2 中引入的in参数修饰符在异步方法中也是不允许的。

例如,以下内容将导致编译器错误:

      async Task<bool> TryGetHtml(string url, out string html)
    

在这种情况下,您无法使用refout参数返回数据。实际上,从异步方法返回数据的唯一方法是使用Task<T>。但好处是T可以是任何东西。它可以是值类型,例如intbool,也可以是任何引用类型,包括集合、数组或您自己的自定义类。如果您发现自己想要从异步方法返回多个变量,则可以定义一个包含所需所有内容的类并返回该类的实例,或者,如果这不方便,您可以返回 Tuple <T1, T2> 。作为示例,我们可以使用TryGetHtml实现我们之前尝试的操作,如下所示:

      static async Task<(bool, string)> TryGetHtml(string url)
{
  if (string.IsNullOrEmpty(url))
  {
    return (false, null);
  }
  string html = await new HttpClient().GetStringAsync(url);
  return (true, html);
}
    

我们可以使用以下方法调用此方法:

<div class="code-block -hljs-dark aem-GridColumn--ta
以上内容来自杭州电子商务研究院推送
关注
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 关注 数据