我有这样的测试代码:
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 ,我们可以读到:
In classes derived from the CriticalFinalizerObject class, the common language runtime (CLR) guarantees that all critical finalization code will be given the opportunity to execute, provided the finalizer follows the rules for a CER, even in situations where the CLR forcibly unloads an application domain or aborts a thread.
这里的主要词是UNLOAD。
其次,让我们阅读MSDN再次,这次是关于托管线程中的异常:
If these exceptions are unhandled in the main thread, or in threads that entered the runtime from unmanaged code, they proceed normally, resulting in termination of the application.
主要词是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
并手动完成您的对象。
更新: Jeffrey Richter 在他的书“CLR via C#”中写到 CriticalFinalizerObject,它适用于将代码发送到 SQLServer 的情况,SQLServer 可以将 C# 作为过程运行。在这种情况下,CriticalFinalizerObject 可以帮助您清理对象,如果 SQLServer 将卸载您的库的域。 此外,CriticalFinalizerObject 适用于您需要在对象的终结器中调用另一个对象的方法的情况,因为 CriticalFinalizerObject 向您保证,它的终结器将在所有非 CriticalFinalizerObject 对象的终结器之后调用。
关于c# - 即使使用 CriticalFinalizerObject,也不会在未处理的异常后调用终结器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10656107/