我有一个.NET Core控制台应用程序。永远不会引发嵌套异步/等待中发生的异常:
static async Task Main(string[] args)
{
try
{
var f = new TaskFactory(TaskScheduler.Current);
await f.StartNew(async () =>
{
var x = 0;
if (x == 0)
throw new Exception("we have a problem");
await Task.Delay(1);
});
}
catch(Exception)
{
// never reaches here
}
}
如果我删除内部的async
,并将呼叫删除到await Task.Delay(1)
,则会捕获到异常。
答案 0 :(得分:5)
那是一个经典的陷阱。 TaskFactory
期望Func<T>
并返回Task<T>
。在您的情况下,T
是Task
,因此您最终得到一个Task<Task>
,并且需要等待内部和外部任务。为此,请使用Unwrap
:
await f.StartNew(async () =>
{
var x = 0;
if (x == 0)
throw new Exception("we have a problem");
await Task.Delay(1);
}).Unwrap();
答案 1 :(得分:2)
您的错误来自StartNew。
当您等待StartNew时,您希望其中的作业能够完成。但是,您提供的工作是创建任务。您的StartNew具有以下返回类型Task<Task>
。
因为它是您的代码在引发感知之前结束。
您可以通过两种不同的方法解决它:
1)您正在等待第一次等待完成后获得的新启动结果
static async Task Main(string[] args)
{
try
{
var f = new TaskFactory(TaskScheduler.Current);
await await f.StartNew(async () =>
{
var x = 0;
if (x == 0)
throw new Exception("we have a problem");
await Task.Delay(1);
});
}
catch(Exception)
{
Console.WriteLine("Exception received");
// never reaches here
}
Console.WriteLine("Done");
}
2)您停止使用StartNew并使用基本的任务模式(我建议)
static async Task Main(string[] args)
{
try
{
await Task.Run(async () =>
{
var x = 0;
if (x == 0)
throw new Exception("we have a problem");
await Task.Delay(1);
});
}
catch(Exception)
{
Console.WriteLine("Exception received");
// never reaches here
}
Console.WriteLine("Done");
}
删除Task.Delay(1)
可以解决问题的原因是,您将StartNew的签名更改为Task而不是Task<Task>
,这使您的单次等待效率很高