我有这样的测试代码:
public class A : CriticalFinalizerObject
{
~A()
{
File.WriteAllText("c:\\1.txt", "1z1z1");
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
throw new Exception();
}
}
首先,我尝试在不从 CriticalFinalizerObject 派生 A 的情况下运行它。此程序结束后未调用终结器。
这让我感到惊讶,因为我认为它更具确定性,但还可以。然后我读了关于 CriticalFinalizerObject 的内容,以确保它们的终结器将被调用。我从中得出A。
你猜怎么着。它仍然没有被执行。
我在做什么/理解错了?
(请不要写关于垃圾收集器不确定性的明显内容,我知道。情况并非如此,因为程序结束了,我想我可以在一个很好的未处理的托管异常之后安全地清理。)
最佳答案
首先,让我们阅读 MSDN 中的 CriticalFinalizerObject ,我们可以阅读,即:
这里的主要词是 UNLOAD 。
其次,让我们再次阅读 MSDN,这次是关于托管线程中的异常:
主要词是 TERMINATION 。
因此,当主线程中存在未处理的异常时 - 应用程序终止,但 CriticalFinalizerObject 仅有助于卸载域。
例如,CriticalFinalizerObject 可以在这种情况下提供帮助:
// Create an Application Domain:
AppDomain newDomain = AppDomain.CreateDomain("NewApplicationDomain");
// Load and execute an assembly:
newDomain.ExecuteAssembly(@"YouNetApp.exe");
//Unload of loaded domain
AppDomain.Unload(newDomain);
在这种情况下,域被卸载,而 CriticalFinalizerObject 向您保证,您的终结器将被调用。
在您终止应用程序的情况下,您可以尝试订阅
AppDomain.CurrentDomain.UnhandledException
并手动完成您的对象。
UPD:
Jeffrey Richter 在他的“CLR via C#”一书中写到了 CriticalFinalizerObject,它适用于将代码发送到 SQLServer 的情况,SQLServer 可以将 C# 作为过程运行。在这种情况下,如果 SQLServer 将卸载库的域,CriticalFinalizerObject 会帮助您清理对象。
此外,CriticalFinalizerObject 用于您需要在对象的终结器中调用另一个对象的方法的情况,因为 CriticalFinalizerObject 向您保证,它的终结器将在所有非 CriticalFinalizerObject 对象的终结器之后被调用。
关于c# - 即使使用 CriticalFinalizerObject 在未处理的异常后也未调用终结器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10656107/