14

Steven Toub 的文章中

为了使开发人员更容易编写基于任务的异步代码,.NET 4.5 更改了未观察到的异常的默认异常行为。虽然未观察到的异常仍会导致引发 UnobservedTaskException 事件(不这样做将是一项重大更改),但默认情况下进程不会崩溃。相反,无论事件处理程序是否观察到异常,异常最终都会在事件引发后被吃掉。

但我的实验结果与上述说法不符。下面是我的代码:

static void Main(string[] args)
{
    DownloadAsync("http://an.invalid.url.com);
}

async static void DownloadAsync(string url)
{
    using (var client = new System.Net.Http.HttpClient())
    {
        string text = await client.GetStringAsync(url);
        Console.WriteLine("Downloaded {0} chars", text.Length);
    }
}

由于我将无效的 url 传递给方法,因此对的DownloadAsync()方法的调用将引发异常,并导致应用程序崩溃。HttpClientGetStringAsync()

所以我的问题是:默认情况下,.NET 4.5 中未观察到的异常是否仍然会使应用程序崩溃?

4

1 回答 1

35

您确实有Task一个例外(由 返回的那个GetStringAsync)。但是,await正在观察Task异常,然后将其传播到DownloadAsync方法之外(即async void)。

从方法中传播出来的异常async void表现不同;它们在方法启动SynchronizationContext时处于活动状态async void(在本例中为线程池SynchronizationContext)引发。这被视为未观察到的异常。

如果您更改DownloadAsync为 return Task,那么您将有一个实际的未观察到的Task异常,它将被忽略(正确地):

static void Main(string[] args)
{
  DownloadAsync("http://an.invalid.url.com);
  Console.ReadKey();
}

async static Task DownloadAsync(string url)
{
  using (var client = new System.Net.Http.HttpClient())
  {
    string text = await client.GetStringAsync(url);
    Console.WriteLine("Downloaded {0} chars", text.Length);
  }
}
于 2013-04-18T23:46:51.820 回答