Try-Catch Async Exceptions

Ben*_*sen 9 c# exception async-await c#-5.0

这个例子"失败":

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

也就是说,文本"失败"的例外会冒泡.

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

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;
}
Run Code Online (Sandbox Code Playgroud)

这也没有帮助.

我想我的Async CTP刷新安装可能会被清除.

这段代码应该像我期望的那样工作("成功"起泡,而不是"失败"),或者这不是"假设"以这种方式工作.如果没有,你会如何解决它?

Arn*_*sen 5

您看到的行为可能是边缘案例错误,甚至可能是正确的,如果不直观.通常,当您同步调用异步方法时,它会执行一个任务来执行,因为没有人等待任务完成,所以异常永远不会进入主线程.如果你直接调用Main会成功,但是你的运行时会在另一个线程上看到"成功"的异常.

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

如果你将main作为一个async方法运行,即返回一个Task(因为一个async返回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);
    }
}
Run Code Online (Sandbox Code Playgroud)

即任务故障,AggregateException其中包含成功异常,因为它是内部异常.