尝试捕获异步异常

10

这个例子“失败”:

static async void Main(string[] args)
{
    try
    {
        await TaskEx.Run(() => { throw new Exception("failure"); });
    }
    catch (Exception)
    {
        throw new Exception("success");
    }
}

也就是说,带有文本“failure”的异常会往上传递。

然后我尝试了这个解决方法:

static async void Main(string[] args)
{
    try
    {
        await SafeRun(() => { throw new Exception("failure"); });
    }
    catch (Exception)
    {
        throw new Exception("success");
    }
}

static async Task SafeRun(Action action)
{
    var ex = default(Exception);
    await TaskEx.Run(() =>
    {
        try
        {
            action();
        }
        catch (Exception _)
        {
            ex = _;
        }
    });
    if (ex != default(Exception))
        throw ex;
}

那也没有帮助。

我猜我的 Async CTP 刷新安装可能出了问题。

这段代码应该按照我的期望工作("success" 上升,而不是 "failure"),还是说本来就不应该这样工作?如果不行,你会怎么处理?

1个回答

5
您看到的行为很可能是边缘情况的错误或者是正确的,但不直观。通常当您同步调用异步方法时,它会包装一个任务进行执行,因为没有人等待任务完成,所以异常不会传递到主线程。如果您直接调用Main,则会成功,但是您的运行时会在另一个线程上看到“成功”的异常。
由于main是应用程序的入口点,它是同步调用的,并且作为入口点可能不会触发Task包装行为,因此await无法正常运行,而TaskEx.Run则在其自己的线程上抛出异常,在运行时显示为在另一个线程上抛出异常。
如果您将main作为async方法运行,即返回Task(因为返回voidasync只能通过await来调用),并在同步的主上下文中阻塞它,则可以得到适当的行为,如下面的测试所示:
static async Task Main() {
    try {
        await TaskEx.Run(() => { throw new Exception("failure"); });
    } catch(Exception) {
        throw new Exception("success");
    }
}

static async Task Main2() {
    await Main();
}

[Test]
public void CallViaAwait() {
    var t = Main2();
    try {
        t.Wait();
        Assert.Fail("didn't throw");
    } catch(AggregateException e) {
        Assert.AreEqual("success",e.InnerException.Message);
    }
    }


[Test]
public void CallDirectly() {
    var t = Main();
    try {
        t.Wait();
        Assert.Fail("didn't throw");
    } catch(AggregateException e) {
        Assert.AreEqual("success", e.InnerException.Message);
    }
}

即任务故障时会出现 AggregateException,其中包含成功异常作为其内部异常。

这是一个用于测试异步的控制台应用程序,因此在我的情况下,顶层方法是Main方法。 - Bent Rasmussen
@Bent,我已经更新了答案以反映你的调用方式,这可能是一个错误,但是由于未定义async入口点而导致的行为。 - Arne Claassen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接