[英]Why can't I catch an exception from async code?
我读到的任何地方都说以下代码应该可以工作,但事实并非如此。
public async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception();
x++;
});
}
catch (Exception ex)
{
// Handle exceptions ?
}
}
也就是说,我没有捕捉到任何东西,并且在“throw”行处得到一个“未处理的异常”。 我在这里一窍不通。
您已打开“仅我的代码”选项。 启用此功能后,它正在考虑未处理的异常与“仅您的代码”有关——因为其他代码正在捕获异常并将其填充到任务中,稍后在await
调用中重新抛出并由您的 catch 语句捕获。
没有附加到调试器中,您的 catch 语句将被触发,它会按您的预期运行。 或者您可以从调试器中继续,它会按预期运行。
最好的办法是关闭“仅我的代码”。 IMO,它引起的混乱超过了它的价值。
正如 SLaks 所说,您的代码运行良好。
我强烈怀疑你过度简化了你的例子,并且在你的代码中有一个async void
。
以下工作正常:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static async void CallAsync()
{
try
{
await DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static Task DoSomething()
{
return Task.Run(() =>
{
throw new Exception();
});
}
以下不起作用:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static void CallAsync()
{
try
{
DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static async void DoSomething()
{
await Task.Run(() =>
{
throw new Exception();
});
}
请参阅http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
异步 void 方法具有不同的错误处理语义。 当异步任务或异步任务方法抛出异常时,该异常将被捕获并放置在任务对象上。 对于 async void 方法,没有 Task 对象,因此从 async void 方法抛出的任何异常都将直接在异步 void 方法启动时处于活动状态的 SynchronizationContext 上引发。 图 2 说明了无法自然捕获从异步 void 方法抛出的异常。
你的代码现在甚至不能像x++;
一样干净地编译x++;
声明无法访问。 始终注意警告。
但是,修复后,它工作正常:
using System;
using System.Threading.Tasks;
class Test
{
static void Main(string[] args)
{
DoSomething(10).Wait();
}
public static async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception("Bang!");
});
}
catch (Exception ex)
{
Console.WriteLine("I caught an exception! {0}", ex.Message);
}
}
}
输出:
I caught an exception! Bang!
(请注意,如果您在 WinForms 应用程序中尝试上述代码,则会出现死锁,因为您将等待需要返回 UI 线程的任务。我们可以在控制台应用程序中作为任务将在线程池线程上恢复。)
我怀疑这个问题实际上只是调试的问题——调试器可能认为它没有被处理,即使它被处理了。
不要使用await
,而是访问Task.Result
属性并try
并catch
该访问。 您也可以按照此处的示例尝试这种风格。
请记住,在任务线程的上下文中抛出的所有异常都包含在AggregateException
。
例外不是cuaght。 原因是 - 执行以下语句时
await Task.Run(() => {
throw new Exception("Bang!");
});
它在一个单独的线程上。 在该线程上引发的异常未被捕获。
将其更改为如下所示
await Task.Run(() => {
try
{
throw new Exception("Bang!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.