AggregateException
我是否因为我没有检查过Exception
房产而得到例外?
不,您会得到一个异常,因为g
TPL 取消了任务(因为,如 msdn 所述,如果前面的任务引发异常,则不会安排此任务)。
我们在这里有 3 个任务:
- 原始任务(使用 StartNew)
- 第一个继续任务(引发异常)
- 第二个继续任务(打印 OK)(这是代码中的 g 任务)。
问题是您要求 TPL仅在第二个任务成功完成时才开始 3d 任务。这意味着如果不满足此条件,TPL 将完全取消您新创建的任务。
您有未观察到的任务异常,因为您有从未观察到的临时任务(我的列表中的任务 2)。一个因为你从来没有观察到它的错误状态,它会抛出终结器来告诉你它。
您可以通过在 catch 块中打印任务的状态来检查这一点:
catch (AggregateException ex)
{
Console.WriteLine("catch");
// Will print: Status in catch: Canceled
Console.WriteLine("Status in catch: {0}", g.Status);
}
我是否必须始终检查先行项是否抛出异常(在每一行中?)?(我不能检查每一行!这没有任何意义而且很烦人)
是的,您应该观察先前的任务异常以避免此问题:
static class TaskEx
{
public static Task ObserverExceptions(this Task task)
{
task.ContinueWith(t => { var ignore = t.Exception; },
TaskContinuationOptions.OnlyOnFaulted);
return task;
}
}
然后按如下方式使用它:
var g= Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ObserveExceptions()
.ContinueWith (a =>{ Console.WriteLine("OK");});
try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{Console.WriteLine("catch"); }
更新:为最后一个项目添加了解决方案
try catch 块不应该吞下异常吗?(我认为所有异常都会冒泡到等待方法......所以?)
我们的项目中有一组扩展方法(称为TransformWith
),可以解决这个特定问题并获得以下收益:
- 异常会冒泡到 catch 块和
- 我们不会让应用程序崩溃
TaskUnobservedException
这里的用法
var g = Task.Factory.StartNew(() => 8)
.ContinueWith(ant => { throw null; })
// Using our extension method instead of simple ContinueWith
.TransformWith(t => Console.WriteLine("OK"));
try
{
Console.WriteLine("1");
// Will fail with NullReferenceException (inside AggregateExcpetion)
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{
// ex.InnerException is a NullReferenceException
Console.WriteLine(ex.InnerException);
}
这是一个扩展方法:
static class TaskEx
{
public static Task TransformWith(this Task future, Action<Task> continuation)
{
var tcs = new TaskCompletionSource<object>();
future
.ContinueWith(t =>
{
if (t.IsCanceled)
{
tcs.SetCanceled();
}
else if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else
{
try
{
continuation(future);
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
}