我们有这个方法:
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
之间是否发生隐式转换?如果不是,那么发生了什么?它是如何实现工作的?
async
关键字来处理这个问题。
Task<> 和 int 之间是否发生隐式转换?
没有。这只是 async
/await
工作原理的一部分。
任何声明为 async
的方法都必须具有以下返回类型:
无效(尽可能避免)
任务(除了完成/失败通知之外没有结果)
Task
编译器会进行所有适当的包装。关键是您异步返回 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;
。)
不需要将 Task 转换为 int。只需使用任务结果。
int taskResult = AccessTheWebAndDouble().Result;
public async Task<int> AccessTheWebAndDouble()
{
int task = AccessTheWeb();
return task;
}
如果可用,它将返回值,否则返回 0。
Result
;它可能会导致死锁!例如,考虑这个工作流程: (1) 写一个说明“修剪草坪”的便条。 (2) 等待修剪草坪 (3) 吃三明治,(4) 做笔记上所说的任何事情”。使用该工作流程,您永远不会吃三明治或修剪草坪,因为第 2 步是 同步等待您将在未来执行的操作。但这就是您在此处描述的工作流程。
不定期副业成功案例分享
async
/await
,我发现这非常不直观。 IMO,在return
中应该有一个关键字或类似的关键字来说明这一点,例如return async result;
(与await result
从Tast<T>
“解包”T
的方式相同)。await
就没有意义 - 使用T foo = someTaskT;
你会得到“无法将类型Task<T>
隐式转换为T
” - 就像我认为它会更有意义有一个反向关键字(包装在Task<T>
中)。我完全赞成去除绒毛,但在这种情况下,我认为它在async
方法中提供了不必要的混淆。 (显然这一点没有实际意义,因为已经说出/编码的权力!)async
,我认为这就足够了。