ChatGPT解决这个技术问题 Extra ChatGPT

Task<int> 是如何变成 int 的?

我们有这个方法:

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<int>int 之间是否发生隐式转换?如果不是,那么发生了什么?它是如何实现工作的?

Keep reading。我假设编译器会根据 async 关键字来处理这个问题。
@Freeman,看看这个很棒的解释:stackoverflow.com/a/4047607/280758

k
kmad1729

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

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

任何声明为 async 的方法都必须具有以下返回类型:

无效(尽可能避免)

任务(除了完成/失败通知之外没有结果)

Task (用于异步方式的 T 类型的逻辑结果)

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

请注意,await 做相反的事情 - 它unwrap Task<T>T 值,这就是该行的工作方式:

string urlContents = await getStringTask;

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

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

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<T> “解包” T 的方式相同)。
@JonSkeet 但是如果没有 await 就没有意义 - 使用 T foo = someTaskT; 你会得到“无法将类型 Task<T> 隐式转换为 T” - 就像我认为它会更有意义有一个反向关键字(包装在 Task<T> 中)。我完全赞成去除绒毛,但在这种情况下,我认为它在 async 方法中提供了不必要的混淆。 (显然这一点没有实际意义,因为已经说出/编码的权力!)
@dav_i: assignment 没有意义,但其余的都有意义。在某些情况下,整个陈述是有意义的——尽管它可能没有用。鉴于该方法已声明为 async,我认为这就足够了。
F
Fábio Nascimento

不需要将 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;'