希望有人在C#中使用async
和await
时可以清除返回类型。我们了解到,您有三种返回类型:Task<T>
,Task
和void
。
通过尝试了解这一点,我已经读过你应该只在特殊情况下使用void
(事件处理程序),如果要将同步方法更改为async
方法,那么你应该更改一个{ {1}}关键字void
。
我的问题是,我是否需要Task
返回类型,即使代码是完全独立的,结果对延续也不重要?比方说,我使用异步方法将一些信息推送到Web服务。
我创建了一个小例子来帮助解释:
Task
我的应用程序有很多这样的方法:
private void CallingMethod()
{
AsyncMethod();
AsyncTaskMethod(); // any difference between doing these? (not exc handling)
var task = AsyncTaskMethod(); // should I do anything with this task
// before I continue? Or is it simply
// just to show the user that it's async??
// continue with unrelated code that doesnt require task or any code from above
}
private async void AsyncMethod() // is void okay?
{
await LongRunningMethod();
// do other stuff
}
private async Task AsyncTaskMethod() // or should it be Task?
{
await LongRunningMethod();
// do other stuff
}
private async Task LongRunningMethod()
{
// do long running code
}
如果不清楚,请务必说出来,我会尝试整理一下。谢谢你们。
编辑:
private void BigMethod()
{
DoStuff();
DoMoreStuff();
AsyncMethod(); // is this right? Or should I have the task declaration too?
UnrelatedStuff();
}
private async Task AsyncMethod() // should this return task?
{
var result = await GetUserId();
if (result == null)
return;
MyUserId = result;
}
private async Task<int> GetUserId()
{
// do long running code
return 1;
}
在回复第一条评论时,上面的private void CallingMethod()
{
AsyncMethod();
}
private async void AsyncMethod()
{
await LongRunningMethod();
}
private async Task LongRunningMethod()
{
await Task.Run(() =>
{
Thread.Sleep(4000);
});
MessageBox.Show("Done!");
}
不使用async / await,它会在没有锁定UI线程的情况下快乐地休眠4秒,然后弹出消息框。问题是什么?
答案 0 :(得分:3)
当方法返回Task
时,您不必 使用void
,但由于以下几个原因,它确实是首选:
返回Task
(或Task<T>
)的异步方法将其异常放在返回的Task
上,因此调用方法可以检查(当他们认为合适时)是否Task
出现了问题。
Async void
方法将它们的异常直接抛出到调用同步上下文中,使它几乎(几乎因为你仍然可以使用全局异常处理程序,但是这样做了对大型应用程序来说无法维护)无法以确定的方式处理它们的异常。
您基本上无法测试任何可能引发异常的async void
方法
async void
方法在调用者运行时被认为是完整的。这可能会引入许多问题(实际上,当您尝试将现有库转换为异步时,事件处理程序存在许多问题:继续,获取第三方相对复杂的winforms库并尝试使您的事件处理程序异步,您和# 39;我会看到它造成的破坏!)。
没有合理的方法可以确定async void
方法何时结束(您可以创建自己的SynchronizationContext
,但这确实很复杂)
您无法配置async void
电话(您无法使用ConfigureAwait
),因此延续上下文始终是来电者的同步上下文。
所以......
TL; DR:除非您无法避免,否则请勿使用async void
(即:使用期望void
签名的事件处理程序)。这是有原因的。如果您不期望结果,请使用async Task
。
答案 1 :(得分:1)
您不能等待返回void
的方法,并且其中一个主要原因是返回void的异步方法的调用者无法捕获从异步方法抛出的异常。试试这个:
public void TryToCatchMethod() {
try {
MyAsyncMethod();
} catch (Exception exception) {
//tha catch is never called
Debug.WriteLine(exception.ToString());
}
}
public async void MyAsyncMethod() {
throw new Exception();
}