9

这个例子“失败”:

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

也就是说,文本“失败”的异常会冒泡。

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

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;
}

那也没有帮助。

我想我的异步 CTP 刷新安装可能会被冲洗掉。

这段代码是否应该按我的预期工作(“成功”冒泡,而不是“失败”),或者这不是“应该”以这种方式工作。如果没有,您将如何解决它?

4

1 回答 1

5

您看到的行为可能是一个边缘案例错误,或者甚至可能是正确的,如果不直观的话。通常,当您同步调用异步方法时,它会包装一个任务来执行,并且由于没有人在等待任务完成,因此异常永远不会进入主线程。如果您直接调用 Main 它会成功,但是您的运行时会在另一个线程上看到“成功”异常。

由于 main 是应用程序的入口点,因此它被同步调用,并且很可能因为入口点不会触发 Task 包装行为,因此 await 无法正常运行并且 TaskEx.Run 会在其自己的线程上抛出,这显示在运行时作为在另一个线程上抛出的异常。

如果您要将 main 作为async方法运行,即返回 a Task(因为返回的 anasync只能void真正通过 via 调用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其中包含成功异常,因为它是内部异常。

于 2011-06-16T19:40:20.893 回答