C# 尝试捕获异步异常
此示例“失败”: 也就是说,文本“failure”的异常出现了 然后我尝试了这个解决方法:C# 尝试捕获异步异常,c#,exception,async-await,c#-5.0,C#,Exception,Async Await,C# 5.0,此示例“失败”: 也就是说,文本“failure”的异常出现了 然后我尝试了这个解决方法: static async void Main(string[] args) { try { await SafeRun(() => { 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刷新安装可以用软管冲洗
这段代码是否应该像我预期的那样工作(“成功”冒泡,而不是“失败”),或者这不是“应该”那样工作。如果不是,您将如何解决它?您看到的行为可能是一个边缘案例错误,或者如果不直观,甚至可能是正确的。通常,当您同步调用异步方法时,它会将任务包装起来执行,因为没有人等待任务完成,所以异常永远不会进入主线程。如果您直接调用Main,它将成功,但是您的运行时将在另一个线程上看到“success”异常 由于main是应用程序的入口点,因此会同步调用它,很可能是因为入口点不会触发任务包装行为,因此wait无法正常运行,TaskEx.run会在自己的线程上抛出,这在运行时会显示为在另一个线程上抛出的异常 如果将main作为
async
方法运行,即返回任务
(因为返回void
的async
只能通过wait
调用)并从同步主上下文对其进行阻塞,那么您将获得适当的行为,如下测试所示:
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);
}
}
也就是说,任务出现了一个
aggregateeexception
,其中包含success异常作为其内部异常。它来自一个用于测试异步的控制台应用程序,因此在我的例子中,顶级方法是主要方法。@Bent我已经更新了答案,以反映您调用的方式,这可能是错误,也可能不是错误,但是是由未定义的异步
入口点行为引起的
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);
}
}