【问题标题】:How does Task<int> become an int?Task<int> 是如何变成 int 的?
【发布时间】:2012-10-20 23:28:36
【问题描述】:

我们有这个方法:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

   // You can do work here that doesn't rely on the string from GetStringAsync.
   DoIndependentWork();

   string urlContents = await getStringTask;
   //The thing is that this returns an int to a method that has a return type of Task<int>
   return urlContents.Length;
}

Task&lt;int&gt;int 之间是否发生隐式转换?如果不是,那么发生了什么?它是如何实现的?

【问题讨论】:

标签: c# .net asynchronous .net-4.5 c#-5.0


【解决方案1】:

不需要将 Task 转换为 int。只需使用任务结果。

int taskResult = AccessTheWebAndDouble().Result;

public async Task<int> AccessTheWebAndDouble()
{
    int task = AccessTheWeb();
    return task;
}

如果可用则返回值,否则返回 0。

【讨论】:

  • 这不是我问的。
  • 这没有回答问题。但更重要的是,这是一个非常糟糕的建议。您几乎应该从不使用Result;它可能会导致死锁!例如,考虑这个工作流程: (1) 写一个说明“修剪草坪”的便条。 (2) 等待修剪草坪 (3) 吃三明治,(4) 做笔记上所说的任何事情”。使用该工作流程,您永远不会吃三明治或修剪草坪,因为第 2 步是 同步等待您将在未来做的事情。但这就是您在此处描述的工作流程。
  • @EricLippert:不清楚你的例子。您能否解释一下 Result 如何在 await 不会引入死锁?
  • 等待意味着在等待结果的同时做某事,并且可以包括做工作来计算结果。但是同步等待在你等待时什么都不做,这意味着你可能会阻止工作完成。
  • @EricLippert。这会有同样的问题吗? 'Task.Run(()=> AccessTheWebAndDouble()).Result;'
【解决方案2】:

Task 和 int 之间是否发生了隐式转换?

不。这只是async/await 工作原理的一部分。

任何声明为async 的方法的返回类型必须为:

  • void(尽可能避免)
  • Task(除了完成/失败通知之外没有结果)
  • Task&lt;T&gt;(用于异步方式的 T 类型的逻辑结果)

编译器会进行所有适当的包装。关键是你异步返回urlContents.Length - 你不能让方法只返回int,因为实际方法将在遇到第一个await表达式时返回'尚未完成。因此,它会返回一个 Task&lt;int&gt;,它会在异步方法本身完成时完成。

请注意,await 的作用正好相反 - 它解开 Task&lt;T&gt;T 值,这就是这条线的工作原理:

string urlContents = await getStringTask;

...但它当然会异步解包,而仅使用Result 会阻塞,直到任务完成。 (await 可以解开实现等待模式的其他类型,但 Task&lt;T&gt; 是您可能最常使用的类型。)

这种双重包装/展开使异步变得如此可组合。例如,我可以编写另一个异步方法来调用你的方法并将结果加倍:

public async Task<int> AccessTheWebAndDoubleAsync()
{
    var task = AccessTheWebAsync();
    int result = await task;
    return result * 2;
}

(当然也可以简单地说是return await AccessTheWebAsync() * 2;。)

【讨论】:

  • 能否提供有关它在后台如何工作的任何细节,只是好奇。
  • +1 一如既往的好答案。为什么你写得这么快?!
  • +1:刚开始研究async/await,我发现这非常不直观。 IMO,return 应该有一个关键字或类似的关键字来说明这一点,例如return async result;(与 await resultTast&lt;T&gt;“解包”T 的方式相同)。
  • @JonSkeet 但是没有await 没有意义 - 使用T foo = someTaskT; 你会得到“无法将类型Task&lt;T&gt; 隐式转换为T” - 以同样的方式我认为为 inverse 设置一个关键字会更有意义(包装在 Task&lt;T&gt; 中)。我完全赞成去除绒毛,但在这种情况下,我认为它在async 方法中提供了不必要的混淆。 (显然这一点没有实际意义,因为已经说出/编码的权力!)
  • @dav_i:assignment 没有意义,但其余的都有意义。在某些情况下,整个陈述是有意义的——尽管它可能没有用。鉴于该方法已经声明为async,我认为这就足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
  • 2017-06-15
  • 2023-04-03
  • 2021-06-04
  • 2018-05-17
相关资源
最近更新 更多