我想我错过了解c#中async
await
的行为。
我有两种方法可以返回Task
定义为
public async Task Name()
{
await AsyncOperation()
}
想象AsyncOperation()
就像PostAsync
HttpClient
一样。
现在我在其他方法中调用它们
public asyn Task Method()
{
await Name1(() => { "bla bla"});
await Name2();
Console.WriteLine("Continue");
}
这对我来说是预期的。等到Name1()
和Name2()
完成然后继续。
现在我需要嵌套Name1()
和Name2()
。实际上Name1()
是一个请求等待窗口,它接收lambda参数是一个缓慢的操作,而Name2()
是一个缓慢的文件下载。我希望在下载文件时出现Plese Wait窗口。
所以我尝试这样的事情:
public asyn Task Method()
{
await Name1( async ()=>
{
await Name2();
}
Console.WriteLine("Continue");
}
在这种情况下,执行不会等待untile Name2()
完成。为什么会发生这种情况并await
不等待?
更新
这是请等待的方法背后的逻辑。它使用Mahapps Dialogs显示Please Wait消息,执行lambda收到的代码,然后关闭请等待消息。
public static async Task Name1(Action longOperation)
{
_progressController = await _metroWindow.ShowProgressAsync("Please wait...");
await Task.Run(() => longOperation());
await _progressController.CloseAsync();
}
答案 0 :(得分:5)
Name1
方法接受委托并返回Task<T>
,其中T
是委托返回的类型。在您的情况下,委托会返回Task
,因此我们会得到Task<Task>
作为结果。使用await
只等待外部任务的完成(它立即返回内部任务),然后忽略内部任务。
你可以通过在lambda函数中删除async和await来解决这个问题。
另外,请查看Asynchronous Gotchas in C#。
答案 1 :(得分:-1)
Name1期望有一个动作参数,但是您真正想要的是一个func。换句话说,Name1应该看起来像这样:
public static double Name1(Func<Task> longOperation)
{
longOperation().Wait();
}
或者,将操作包装在函子中,然后等待。
public static double Name1(Action longOperation)
{
Func<Task> f = async () => { longOperation(); };
f.Wait();
}
如果您等待异步子,则子将在后台运行,但不会阻止调用方法的继续执行。
如果要执行子程序并等待其完成,然后再继续下游逻辑,则将异步子程序转换为异步函数(当没有实际返回值时,结果类型为threading.tasks.task)。
此站点上有一些很好的例子,这些例子说明了人们在异步等待中犯的常见错误: https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/