为什么我不能从异步代码中捕获异常?

时间:2013-11-08 17:55:53

标签: c# .net c#-5.0

我读到的每个地方都说下面的代码应该可行,但事实并非如此。

public async Task DoSomething(int x)
{
   try
   {
      // Asynchronous implementation.
      await Task.Run(() => {
      throw new Exception();
      x++;
      });
   }
   catch (Exception ex)
   {
      // Handle exceptions ?
   }
}

那就是说,我没有抓到任何东西,并且在“投掷”线上得到一个“未处理的例外”。我在这里很傻。

5 个答案:

答案 0 :(得分:30)

您已打开“仅我的代码”选项。有了这个,它正在考虑关于“只是你的代码”未处理的异常 - 因为其他代码正在捕获异常并将其填充到Task中,稍后在await调用时重新抛出并被捕获你的捕获声明。

如果没有附加在调试器中,您的catch语句将被触发,并且它将按预期运行。或者您可以从调试器中继续运行,它将按预期运行。

更好的办法就是关闭“只是我的代码”。国际海事组织,它引起的混乱比它值得多。

答案 1 :(得分:10)

正如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

  

Async void方法具有不同的错误处理语义。当一个   异常被抛出异步任务或异步任务方法,即   捕获异常并将其放在Task对象上。用async void   方法,没有Task对象,所以抛出任何异常   异步void方法将直接引发   在async void方法时处于活动状态的SynchronizationContext   开始。图2说明了异步void抛出的异常   方法无法自然捕获。

答案 2 :(得分:8)

由于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线程的任务。我们在控制台应用程序中没问题因为任务将在线程池线程上恢复。)

我怀疑问题实际上只是调试问题 - 调试器可能认为它未处理,即使 处理。

答案 3 :(得分:-1)

不使用await,而是访问Task.Result属性,并在该访问权限周围添加trycatch。您也可以按照示例here进行尝试。

请记住,在任务线程的上下文中抛出的所有异常都包含在AggregateException中。

答案 4 :(得分:-2)

例外不是真的。 原因是 - 当执行以下语句时

await Task.Run(() => {
            throw new Exception("Bang!");
        });

它在一个单独的线程上。该线程引发的异常没有被捕获。

将其更改为如下所示

await Task.Run(() => {

                try
                {
                    throw new Exception("Bang!");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);   
                }

        });