Task <int>如何变成int?


116

我们有这种方法:

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?如果没有,那是怎么回事?如何实施工作?


1
继续阅读。我假设编译器会根据async关键字来处理该问题。
D Stanley

1
@Freeman,请看下面这个很好的解释:stackoverflow.com/a/4047607/280758
qehgt 2012年

Answers:


171

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

不。这只是async/ await工作方式的一部分。

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

  • void (尽可能避免)
  • Task (没有完成/失败通知的结果)
  • Task<T>(对于T异步类型的逻辑结果)

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

请注意,await则正好相反-它解开Task<T>到一个T值,这是此行是如何工作的:

string urlContents = await getStringTask;

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

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

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

(或者return await AccessTheWebAsync() * 2;当然就是简单地。)


3
可以好奇地提供有关其如何工作的任何细节。
Freeman

8
+1答案一如既往。为什么你这么快写它们呢?
Felix K.

9
+1:刚开始研究async/时await,我发现这非常不直观。IMO,应该有一个关键字或类似的return,以明确这一点,例如return async result;(在相同的方式,await result“解开的” TTast<T>)。
dav_i 2013年

2
@JonSkeet但是,如果没有await- 没有意义,因为T foo = someTaskT;您将得到“无法将类型隐式转换Task<T>T”-同样,我认为为逆词使用关键字(在中包装Task<T>)会更有意义。我全力以赴去除绒毛,但在这种情况下,我认为它在async方法内提供了不必要的混淆。(显然,这是有争议的,因为已经说/编码过的能力!)
dav_i

2
@dav_i:分配没有意义,但其余部分有意义。在某些情况下,整个语句会很有意义-尽管可能没有用。鉴于已经声明了该方法async,我认为就足够了。
乔恩·斯基特

18

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

int taskResult = AccessTheWebAndDouble().Result;

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

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


20
那不是我问的。
弗里曼

16
这不能回答问题。但是更重要的是,这是非常糟糕的建议。你应该几乎不要使用Result; 可能导致死锁!例如,考虑以下工作流程:(1)写下“修剪草坪”的注释。(2)等待草坪割草(3)吃三明治,(4)照纸条上的说明进行操作。“在该工作流程中,您永远不会吃三明治或割草,因为步骤2是同步等待的东西,你会做在未来但是,这是工作流程,你所描述这里。
埃里克利珀

@EricLippert:不清楚您的示例。您能否解释一下在等待时结果将如何引入死锁?
CharithJ

3
等待是指在等待结果时执行某项操作,并且该操作可能包括进行工作以计算结果。但是同步等待在您等待时什么也没做,这意味着您可能无法完成工作。
埃里克·利珀特

1
@EricLippert。这会有同样的问题吗?'Task.Run(()=> AccessTheWebAndDouble())。Result;'
CharithJ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.