我有这个简单的代码:
var g= Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ContinueWith (a =>{ Console.WriteLine("OK");},TaskContinuationOptions.NotOnFaulted);
try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{Console.WriteLine("catch"); }
输出:
1
catch
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
msdn:
TaskContinuationOptions.NotOnFaulted
指定不应安排延续任务 先行者抛出了一个未经处理的例外。此选项无效 多任务延续。
好的。
没关系 - 不显示此行会导致prev行DID抛出异常。
问题:
我是否收到AggregateException
例外,因为我没有检查Exception
属性?
我必须始终检查前提是否会抛出异常(在每一行?)? (我无法检查每一行!它没有任何意义且非常烦人)
try catch
块不应该吞下异常吗? (我认为所有异常都会导致等待方法....所以?)
答案 0 :(得分:5)
我是否收到
AggregateException
例外,因为我没有检查过Exception
属性?
不,你得到一个例外,因为任务g
被TPL取消(因为,如msdn所述,如果antescendent任务抛出异常,则不会安排此任务。)
我们这里有3个任务:
问题是,只有第二项任务成功完成,才会要求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
),可以解决这个特定问题并获得以下内容:
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;
}
}
答案 1 :(得分:3)
我是否收到了AggregateException异常,因为我没有检查过 异常属性?
任务总是抛出AggregateException:http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.exception.aspx
您可以使用以下方式获取原始异常:
var myTask = Task.Factory.StartNew(() => { throw new NotImplementedException(); });
var myException = myTask.Exception.Flatten().InnerException as NotImplementedException;
我必须始终检查先前是否会抛出异常(在每个中 线? )? (我不能检查每一行!它没有任何意义和 非常讨厌)
是的,这很烦人,你应该为每个任务创建两个延续来检查异常:一个检查是否有异常来处理异常,另一个继续操作,如果没有异常,请参阅{{1} }和TaskContinuationOptions.OnlyOnFaulted
。
如果需要,你甚至应该创建第三个延续来处理取消。
是不是try catch块应该吞下异常? ( 一世 以为所有异常都会导致等待方法....所以? )
TaskContinuationOptions.OnlyOnRanToCompletion
来检查是否存在异常。只有在.net 4 中没有的async关键字,您才能在来电者级别获取任务例外情况
答案 2 :(得分:0)
处理像这样的AggregateExceptions:
catch(AggregateException aex)
{
aex.Handle(ex =>
{
// Do some handling and logging
return true;
}
}