【问题标题】:static destructor静态析构函数
【发布时间】:2011-05-20 20:43:19
【问题描述】:

C# 具有静态构造函数,可以进行一些初始化(可能会进行一些非托管资源初始化)。

我想知道是否有静态析构函数?

【问题讨论】:

  • +1 这个有趣的评论,leppie。我想指出,静态资源与应用程序的生命周期基本相同。当应用程序死亡时,它们也会死亡。因此,不需要静态析构函数。
  • “所以不需要静态析构函数”——这两件事有什么关系?因为它只会在卸载 appdomain 时发生,所以突然没有必要了?我不确定我是否遵循那里的逻辑。

标签: c# .net


【解决方案1】:

不完全是析构函数,但你可以这样做:

class StaticClass 
{
   static StaticClass() {
       AppDomain.CurrentDomain.ProcessExit +=
           StaticClass_Dtor;
   }

   static void StaticClass_Dtor(object sender, EventArgs e) {
        // clean it up
   }
}

【讨论】:

  • 虽然事件 似乎 在 AppDomain 上,但实际上它仅在默认域退出(即最后一个域)时触发,就在整个应用程序终止之前。当卸载任何其他 AppDomain 时,它不会触发,这本身会导致大多数类型和类型的实例被破坏(但并非总是如此)。此事件不是guaranteed to always fire.
  • 我建议不要将敏感的清理操作留给静态实例的解构,并且遵循此建议,您永远不必担心此事件不会触发。我从来没有遇到过这个事件没有触发的问题(即使应用程序中发生了意外的异常)。通过任务管理器终止进程与意外异常有很大不同。你是对的,如果用户通过操作系统任务管理系统杀死程序,它不会触发。
  • 将销毁代码添加到 Main() 方法的末尾是否是个好主意,从那里创建应用程序域?
【解决方案2】:

这是最好的方法(参考:https://stackoverflow.com/a/256278/372666

public static class Foo
{
    private static readonly Destructor Finalise = new Destructor();

    static Foo()
    {
        // One time only constructor.
    }

    private sealed class Destructor
    {
        ~Destructor()
        {
            // One time only destructor.
        }
    }
}

【讨论】:

  • 这种方式保证有效! :) 试一试,如果有人感兴趣,我有单元测试证明它有效?
  • 而且它是一种独立于环境的方式(构建在语言逻辑内部)
  • 不幸的是,这保证有效。根据 Raymond Chen 关于 Garbage Collection 终结器的文章不可靠,因为不能保证 GC 会运行。
  • @McGuireV10(我并不是说你在这里错了),但是关于 Finalizers 的官方文档并没有提到 Raymond 所说的 docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…,如果能听到微软关于他 2010 年的文章是否(或仍然)准确?在我对上述的所有测试中,我从来没有能够触发终结器没有被调用的情况......如果我的上述建议不正确,那么我想更新/如果是这种情况,请删除它,但我认为我们需要更有力的证据。
  • @TodThomson 对于 .NET Framework,~Object Remarks 部分列出了无法保证终结器的一些情况,并且您链接的文档指出在 .NET Core 下关闭时不会调用它们。不幸的是,MS 文档的质量已经不如从前了。
【解决方案3】:

不,没有。

静态析构函数应该会在进程执行结束时运行。当一个进程死亡时,与其相关的所有内存/句柄都将被操作系统释放。

如果您的程序应该在执行结束时执行特定操作(如事务数据库引擎,刷新其缓存),那么正确处理将比仅在结束时运行的一段代码困难得多进程的正常执行。您必须手动处理进程的崩溃和意外终止,并尝试在下次运行时恢复。 “静态析构函数”概念并没有太大帮助。

【讨论】:

  • 在我的例子中,我使用的是需要释放的操作系统范围的互斥锁,否则它会在应用程序的下一次运行时抛出 AbandonedMutexException。在这种情况下,程序结束时释放的内存和句柄并没有考虑到我的 Mutex。您在第 3 段中所说的可能是一种管理它的方法,但应用程序发布的结束对我来说似乎更有意义。
【解决方案4】:

不,没有。您可以做的最接近的事情是设置事件处理程序 到AppDomain 上的DomainUnload 事件并在那里执行清理。

【讨论】:

  • 这实际上是获得更高支持的Process_Exit 建议的一种更受欢迎的方法,这是完全不同的。静态 ctor 触发后类型的生命周期通常是程序集的生命周期,该程序集与 AppDomain 一起卸载。
  • 这对我来说是最简单且影响最小的解决方案。在我的上下文中,挂接到 Process_Exit 不起作用,但 DomainUnload 起作用。
  • 但是DomainUnload 没有被调用default domain
【解决方案5】:

从静态实现中初始化和清理非托管资源是很成问题的并且容易出现问题。

为什么不使用单例,并为实例实现Finalizer(理想情况下继承自SafeHandle

【讨论】:

    【解决方案6】:

    没有什么类似于静态类的析构函数,但如果你真的需要做某事,你可以使用Appdomain.Unloaded 事件

    【讨论】:

      猜你喜欢
      • 2021-08-19
      • 2018-05-07
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 2015-12-27
      相关资源
      最近更新 更多