7

在以前的 MonoTouch 版本中,我曾经这样做以忽略未观察到的异常:

TaskScheduler.UnobservedTaskException += delegate(object sender, UnobservedTaskExceptionEventArgs e) {
    Console.WriteLine (e);
    e.SetObserved ();
};

这是否是一个好的做法是有争议的,但我想知道使用Xamarin.iOS 6.4 现在正式支持的async/await关键字来达到相同的效果。

这是我用于测试的代码:

async void OnClick (object sender, EventArgs e)
{
    await Task.Run (() => { throw new Exception (); });
}

当我运行它时,调试器暂停AsyncVoidMethodBuilder

在此处输入图像描述

我读到 .NET 4.5 应该改变了行为,因此未观察到的异常不会使应用程序崩溃——但是如果将异常发布到我无法处理的 UIKit 同步上下文中,这将无济于事。

有没有办法忽略awaitMonoTouch 中未观察到的异常?

4

1 回答 1

7

这是async void方法的正确行为:它们应该引发方法启动SynchronizationContext时处于活动状态的异常。async void

您在 .NET 4.5 中提到的更改仅处理未观察到的任务异常,不适用于async void方法。

在(Microsoft).NET 世界中,不同SynchronizationContext的实现具有不同的顶级错误处理。WPF、WinForms 和 ASP.NET 都有不同的方法来处理该错误,通常作为Application类型的一部分。

我查看了 Mono 的 UIKit API——虽然我不是普通的 Mono 用户——但在 中找不到任何顶级错误处理UIApplication,而且UIKitSynchronizationContext看起来它不是公开的(或至少没有记录)。

看待这个问题的另一种方式:async void方法的异常处理行为被设计成就像事件处理程序一样(有关更多信息,请参阅我的 MSDN 文章)。所以你可以用另一个问题来回答这个问题:在 UIKit 中,你将如何处理这个异常?

void OnClick (object sender, EventArgs e)
{
  throw new Exception();
}

您将以async void完全相同的方式处理您的异常。

或者,如果您想继续使用UnobservedTaskException,您可以根本不观察任务异常(在您的async void代码中,Task.Run返回一个获得异常的任务,并且您正在通过 using 观察它await):

void OnClick (object sender, EventArgs e)
{
  Task.Run(() => { throw new Exception(); });
}

但是,我建议使用async voidfor 事件处理程序和(最终)awaiting 所有任务。这将确保您不会收到任何“静默错误”(忽略的任务异常),您的程序只是停止正常工作并且您不知道为什么。

于 2013-07-25T12:59:00.690 回答