据我所知,没有直接的答案。
如果你想编写一个健壮的DLL,你应该为以下几种情况做好准备:
- 您的代码托管在默认 AppDomain 中的 .NET 应用程序中。 (琐碎的场景)
- 您的代码托管在 .NET 应用程序中,位于由托管代码创建的 AppDomain 中。
- 您的代码托管在非托管应用程序(托管 CLR)中。
第三种情况是最难处理的,因为 CLR 可以被其主机禁用,因此托管代码将不再执行。
System.Windows.Forms.Application.ApplicationExit
没有什么好处,因为它只适用于 WinForm 应用程序。
System.AppDomain.DomainUnload
其本身并没有什么好处,因为它永远不会为默认的 AppDomain 引发。
AppDomain.ProcessExit
本身并没有什么好处:如果您的代码托管在单独的 AppDomain 中,则主机可能会卸载该 AppDomain,因此该事件永远不会引发。
我首先尝试使用以下内容来涵盖大多数情况:
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
AppDomain.CurrentDomain.ProcessExit += MyTerminationHandler;
else
AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler;
但请注意以下评论(来自 MSDN):
所有 ProcessExit 事件处理程序的总执行时间都是有限的,就像所有终结器的总执行时间在进程关闭时也是有限的一样。默认值为两秒。非托管主机可以通过使用 OPR_ProcessExit 枚举值调用 ICLRPolicyManager::SetTimeout 方法来更改此执行时间。
上面的代码仍然没有考虑第三种情况。
我知道有两种方法可以处理这种情况(以及前两种)
首先,您可以使用System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup
方法,如下:
{
// this goes at your code's entry point
RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(MyExecutionCode, MyCleanupCode, null);
}
static void MyExecutionCode(object data) { /* your execution code here */}
static void MyCleanupCode(object data, bool exceptionThrown) { /* your cleanup code here */ }
其次,您可以利用System.Runtime.ConstrainedExecution.CriticalFinalizerObject
class (请参阅此处的 MSDN)通过继承它并将清理代码放入终结器中。这要求您的清理代码遵守约束执行区域指导方针。