【问题标题】:Try-Catch Async ExceptionsTry-Catch 异步异常
【发布时间】:2011-09-16 15:44:33
【问题描述】:

这个例子“失败”:

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 刷新安装可能会被破坏。

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

【问题讨论】:

    标签: c# exception async-await c#-5.0


    【解决方案1】:

    您看到的行为可能是一个边缘案例错误,甚至可能是正确的,如果不直观的话。通常,当您同步调用异步方法时,它会包装一个任务以执行,并且由于没有人在等待任务完成,因此异常永远不会进入主线程。如果您要直接调用 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);
        }
    }
    

    即Task 出现 AggregateException 错误,其中包含 success 异常,因为它是内部异常。

    【讨论】:

    • 它来自用于测试异步的控制台应用程序,因此在我的情况下,顶级方法是 Main 方法。
    • @Bent 我已经更新了答案以反映您的调用方式,这可能是也可能不是错误,但由 async 入口点未定义行为引起
    猜你喜欢
    • 1970-01-01
    • 2011-04-01
    • 2013-03-09
    • 2015-06-21
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多