36

我读到的所有地方都说下面的代码应该可以工作,但事实并非如此。

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

也就是说,我没有捕捉到任何东西,并得到一个源自“抛出”行的“未处理异常”。我在这里一无所知。

4

5 回答 5

36

您已打开“仅我的代码”选项。启用此选项后,它正在考虑“仅您的代码”未处理的异常 - 因为其他代码正在捕获异常并将其填充到 Task 中,稍后在await调用时重新抛出并被您的 catch 语句捕获。

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

最好的办法是关闭“只是我的代码”。IMO,它引起的混乱比它的价值更多。

于 2013-11-08T20:44:12.643 回答
14

正如 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 方法具有不同的错误处理语义。当异步任务或异步任务方法抛出异常时,会捕获该异常并将其放置在任务对象上。对于 async void 方法,没有 Task 对象,因此从 async void 方法抛出的任何异常都将直接在 async void 方法启动时处于活动状态的 SynchronizationContext 上引发。图 2 说明了从 async void 方法抛出的异常不能自然地被捕获。

于 2013-11-08T18:10:38.553 回答
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 线程的任务。我们可以在控制台应用程序中作为任务将在线程池线程上恢复。)

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

于 2013-11-08T18:02:22.797 回答
-1

而不是使用await,访问该Task.Result属性并在该访问权限周围放置一个tryand catch。您也可以按照此处的示例尝试该样式。

请记住,在任务线程的上下文中引发的所有异常都包含在AggregateException.

于 2013-11-08T17:59:47.530 回答
-2

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

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

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

将其更改为如下所示

await Task.Run(() => {

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

        });
于 2014-07-23T14:35:59.453 回答