延迟和递归
本文关键字:递归 延迟 | 更新日期: 2023-09-27 18:10:00
我试图写一个函数,将测试一些条件并返回一个值,但如果条件不满足,它将等待,然后再试一次。当然,我可以扔进一个Thread.Sleep
,但我认为我应该能够用任务和asynch
/await
来完成这个任务,但我不能完全击中正确的语法来完成这个工作。例如:
public async Task<T> Get<T>(TimeSpan waittime)
{
if (someCondition)
{
return SomeFunctionThatReturnsValue<T>();
}
else
{
return await Get<T>(waitime);
}
}
工作,但没有任何延迟(显然),所以我尝试了多种变体,如:
public async Task<T> Get<T>(TimeSpan waittime)
{
if (someCondition)
{
return SomeFunctionThatReturnsValue<T>();
}
else
{
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime));
}
}
但是这给了我编译时的错误:
Error 52 Since this is an async method, the return expression must be of type 'T' rather than 'Task<T>'
我可以将最后的return
更改为:
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waittime).Result);
它可以编译,但看起来也不完全正确
由于您希望您的方法是异步的,当您想要获得Task
的结果时,您应该使用await
,而不是Result
,以便操作是异步执行的,因此您可以将该操作编写为:
return await await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime));
或者,当你有两个等待时,你可以使用Unwrap
代替;这并不是真的更好或更坏;这是等价的:
return await Task.Delay(waittime).ContinueWith(t => Get<T>(waitime)).Unwrap();
请注意,通过使用Unwrap
,你也可以使方法不是async
,而不是await
,因为Unwrap
已经在做把你的Task<Task<T>>
变成Task<T>
的工作。
当然,在大多数情况下,您通常不应该在async
方法中使用ContinueWith
,您应该简单地使用await
将continuation附加到您的任务:
await Task.Delay(waittime)
return Get<T>(waitime);
同样值得注意的是,您应该在这里真正使用while
循环,而不是使用递归,特别是因为您有一个async
方法,这意味着为每个递归调用构建另一个状态机。