根据我的研究,我了解到以下几点:TaskScheduler.UnobservedTaskException
必须等待任务被垃圾回收,然后该任务的未观察到的异常才会冒泡到UnobservedTaskException
事件。
如果您使用的是Task.Wait()
,则无论如何都不会调用它,因为您阻止了Task即将发生的结果,因此该异常将抛出在Task.Wait()
上,而不是冒泡到UnobservedException
事件。
除非您确切地知道自己在做什么,否则手动调用GC.Collect()
通常是一个坏主意,因此在这种情况下确认事情非常有用,但不能作为问题的适当解决方案。
问题
如果我的应用程序在垃圾收集器启动之前退出,我绝对100%无法触发我的UnobservedTaskException
事件。
请注意以下代码:
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Task.Factory.StartNew(() =>
{
Console.WriteLine("Task started.");
throw new Exception("Test Exception");
});
Thread.Sleep(1000);
//GC.Collect();
//GC.WaitForPendingFinalizers();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText(@"C:\data\TestException.txt", e.Exception.ToString());
Console.WriteLine("UNOBSERVED EXCEPTION");
}
}
没有写入异常文件,也没有任何内容写入控制台。应用程序退出后可能需要10到15分钟甚至更长的时间,但我仍然看不到有证据表明我的应用程序的残骸已被垃圾回收。您可能会问,为什么不只在出口处收款?好吧,我的现实情况是我的异常陷阱运行在Windows服务内部托管的WCF服务内部。我无法捕获Windows服务关闭(并因此手动调用
GC.Collect()
)的时间,因为据我所知,没有任何事件发生。我要去哪里错了?如何确保如果WCF服务内部的某些内容最终将破坏Windows服务,那么我有机会在服务崩溃之前记录该异常?
最佳答案
对我来说,TaskScheduler.UnobservedTaskException最初给人一种非常错误的安全感。如果依赖于垃圾回收,那确实不值多少钱。
我发现以下取自this msdn article的解决方案更加可靠。仅当task1中存在未处理的异常时,它基本上才执行延续块(在其中记录异常),并且不阻止UI执行。
您可能还希望拼合嵌套的AggregateExceptions并创建扩展方法,如Reed Copsey depicted here。
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
{
Console.WriteLine("I have observed a {0}",
t.Exception.InnerException.GetType().Name);
},
TaskContinuationOptions.OnlyOnFaulted);
关于.net - TaskScheduler.UnobservedTaskException永远不会被调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3973315/