2011-06-16 104 views
8

这个例子 “失败”:的try-catch异步异常

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

这段代码应该如我所期望的那样工作(“成功”起来,而不是“失败”),或者这不是“假设”以这种方式工作。如果不是,你将如何解决它?

回答

5

您看到的行为可能是边缘案例错误,或者甚至可能是正确的,如果不直观的话。通常,当你同步调用一个异步方法时,它会绕过一个任务执行,并且由于没有人等待任务完成,所以异常不会将其传递到主线程。如果你直接调用Main,它会成功,但是你的运行时会在另一个线程上看到“成功”的异常。

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

如果您要运行主要为async方法,即返回Task(因为它返回void真的只能通过await被称为async),并从同步的主要方面阻止它,你会得到适当的行为如下面的测试所示:

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

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

+0

它来自一个控制台应用程序,用于测试异步,所以顶级方法是我的情况下的主要方法。 – 2011-06-16 21:58:38

+0

@Bent我已经更新了答案,以反映你如何调用,这可能是也可能不是错误,但是由'async'入口点引起的未定义行为 – 2011-06-18 16:25:22