use*_*007 14 c# exception task
我试图了解在任务对象中引发但从未处理的异常发生了什么.
在MSDn上,据说:
如果您不等待传播异常的任务或访问其Exception属性,则在对任务进行垃圾回收时,将根据.NET异常策略升级异常.
所以我不太明白这些异常会以何种方式影响程序流程.我认为这些异常应该在垃圾收集后立即中断执行.但我无法设计这种行为.在以下代码段中,抛出的异常不会显示.
// Do something ...
Task.Run (()=> {throw new Exception("Exception in the task!");});
// Do something else
Run Code Online (Sandbox Code Playgroud)
请问,任何人都可以解释如何处理未处理的任务异常,以及它们如何影响程序流程.
Dam*_*Arh 31
您正在描述.NET 4中的行为,但是您很难强制执行垃圾收集并实际观察该行为.以下引自斯蒂芬·图布(Stephen Toub)关于这一主题的优秀文章,应该更清楚:
任务跟踪是否"观察到未处理的异常".在此上下文中,"观察"意味着代码以某种方式与Task连接,以便至少知道异常.这可能是在Task上调用Wait/WaitAll.任务完成后,可以检查Task的Exception属性.或者它可能正在使用Task的Result属性.如果一个任务看到它的异常已经以某种方式被观察到,那么生活是美好的.但是,如果删除了对Task的所有引用(使Task可用于垃圾收集),并且如果尚未观察到它的异常,则Task知道永远不会观察到它的异常.在这种情况下,Task利用finalization,并使用辅助对象在终结器线程上传播未处理的异常.使用前面描述的行为,终结器线程上的该异常将被取消处理并调用默认的未处理异常逻辑,即记录问题并使进程崩溃.
他还提出了两个有用的扩展方法来处理"即发即弃"任务中的异常:一个忽略异常,另一个立即崩溃进程:
public static Task IgnoreExceptions(this Task task)
{
task.ContinueWith(c => { var ignored = c.Exception; },
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.DetachedFromParent);
return task;
}
public static Task FailFastOnException(this Task task)
{
task.ContinueWith(c => Environment.FailFast(“Task faulted”, c.Exception),
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.DetachedFromParent);
return task;
}
Run Code Online (Sandbox Code Playgroud)
在.NET 4.5中,默认行为已更改.再一次,引自另一个Stephen Toub关于这个主题的帖子(感谢mike z在评论中引起我的注意):
为了使开发人员更容易编写基于Tasks的异步代码,.NET 4.5更改了未观察到的异常的默认异常行为.虽然未观察到的异常仍会导致引发UnobservedTaskException事件(不会这样做会发生重大变化),默认情况下进程不会崩溃.相反,无论事件处理程序是否观察到异常,异常将在引发事件后最终被吃掉.但是,可以配置此行为.
请注意上面的代码并不完全正确。您必须返回指向 的指针task.ContinueWith
,而不是传入的任务:
public static Task IgnoreExceptions(this Task task)
{
var t = task.ContinueWith(c => { var ignored = c.Exception; },
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
return t;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
这是具有挑战性的,因为这取决于您如何将调用链接在一起。例如,以下调用无法按我预期的方式工作:
public Task MyServiceCall()
{
return Task.Run(() => DoSomething()).IgnoreExceptions();
}
Run Code Online (Sandbox Code Playgroud)
这个方法确实抛出异常,因为接受的答案返回初始任务(不是观察异常的任务)。这可能是与其他调用,如存在问题.Wait
,.WhenAll
等等。有人可能会认为该任务将永远不会丢,但它可以。
但是,我建议的更改会破坏以下内容:
public void SomeMethod()
{
var myTask = new Task(() => ...);
myTask.IgnoreExceptions().Start();
}
Run Code Online (Sandbox Code Playgroud)
在内部我们决定废弃这个扩展方法,因为它太混乱了!
归档时间: |
|
查看次数: |
5961 次 |
最近记录: |