此示例“失败”:
static async void Main(string[] args)
{
try
{
await TaskEx.Run(() => { throw new Exception("failure"); });
}
catch (Exception)
{
throw new Exception("success");
}
}也就是说,会出现文本为"failure“的异常。
然后我尝试了这个变通方法:
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刷新安装可能是软管。
这段代码应该像我期望的那样工作(“成功”,而不是“失败”),或者这不是“应该”工作的方式。如果不是,你将如何解决它?
发布于 2011-06-17 03:40:21
您看到的行为很可能是边缘案例错误,或者甚至可能是正确的,如果不直观的话。通常,当您同步调用异步方法时,它会包装一个任务来执行,因为没有人等待任务完成,所以异常永远不会到达主线程。如果你直接调用Main,它会成功,但是你的运行时会在另一个线程上看到一个“成功”的异常。
由于main是应用程序的入口点,因此它可能会被同步调用,因为入口点不会触发任务包装行为,因此await不能正确运行,TaskEx.Run会在自己的线程上抛出异常,这在运行时显示为在另一个线程上抛出的异常。
如果您将main作为async方法运行,即返回一个Task (因为返回void的async实际上只能通过await调用)并从同步main上下文中阻塞它,您将获得适当的行为,如下面的测试所示:
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);
}
}也就是说,任务通过包含success异常作为其内部异常的AggregateException出错。
https://stackoverflow.com/questions/6377150
复制相似问题