我有这样的测试代码:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
首先,我尝试在不从CriticalFinalizerObject派生A的情况下运行它.在该程序结束后没有调用终结器.这令我感到惊讶,因为我认为这更具确定性,但没关系.然后我读到了关于CriticalFinalizerObject的内容,确保调用它们的终结器.我从它那里得到了A. 你猜怎么着.它仍然没有被执行.我在做什么/理解错误?
(请不要写关于垃圾收集器是非确定性的明显的东西,我知道.事实并非如此,因为程序结束了,我想我可以安全地清理一个很好的未处理的托管异常.)
首先,让我们了解CriticalFinalizerObject在MSDN中,我们可以读出,即:
在从CriticalFinalizerObject类派生的类中,公共语言运行库(CLR)保证所有关键的最终化代码都有机会执行,前提是终结器遵循CER的规则,即使在CLR强制卸载应用程序域的情况下也是如此或中止一个帖子.
这里的主要词是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);
Run Code Online (Sandbox Code Playgroud)
这是一种情况,其中域已被卸载,而CriticalFinalizerObject保证您将调用终结器.
在终止应用程序的情况下,您可以尝试订阅
AppDomain.CurrentDomain.UnhandledException
Run Code Online (Sandbox Code Playgroud)
并手动完成对象.
UPD: Jeffrey Richter在他的书"CLR via C#"中写了一篇关于CriticalFinalizerObject的文章,它是针对您将代码发送到SQLServer的情况,SQLServer可以将C#作为程序运行.在这种情况下,如果SQLServer将卸载您的库的域,CriticalFinalizerObject可以帮助您清理对象.此外,CriticalFinalizerObject适用于您需要在对象的终结器中调用另一个对象的方法的情况,因为CriticalFinalizerObject保证您将在所有非CriticalFinalizerObject对象的终结器之后调用它的终结器.
| 归档时间: |
|
| 查看次数: |
1143 次 |
| 最近记录: |