延迟和递归

Delay and recurse

我正在尝试编写一个函数来测试某些条件和 return 一个值,但如果不满足条件,它会等待,然后重试。当然,我可以只输入一个 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 将延续附加到您的任务:

await Task.Delay(waittime)
return Get<T>(waitime);

同样值得注意的是,你真的应该在这里使用 while 循环,而不是使用递归,特别是因为你有一个 async 方法,这意味着构建 另一个 每个递归调用的状态机。