静态类应该在“静态析构函数”中处理其IDisposable变量的释放吗?

4
如果一个静态类有任何IDisposable静态变量,那么该类是否需要有一个"静态析构函数"来处理这些变量呢?例如:
public static StaticClass
{
    static SomeDisposableType
        someDisposable = new SomeDisposableType();

    static readonly StaticDestructor
        staticDestructor = new StaticDestructor();

    private sealed class StaticDestructor
    {
        ~StaticDestructor()
        {
            someDisposable.Dispose();
        }
    }
}

4
最佳实践可能是不要对这些类型的内容使用静态类,使用作用域单例可能更好。如果确实需要这样做,则在关闭之前手动释放它们,因为不能保证会运行终结器。 - TheGeneral
这个类应该有一个“静态析构函数”来处理它们吗?不需要。特别是因为析构函数不应该像那样调用Dispose - http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/ / https://devblogs.microsoft.com/cbrumme/finalization/ 。即使如此 - 什么时候是调用终结器的正确时间呢? - mjwills
2个回答

2
不,不应该这样做。
运行时无法知道静态类何时被最后一次使用。因此,它无法知道何时调用清理操作。
因此,执行清理的唯一“合理”时间是整个进程即将终止的时候。但那也不是正确的清理时间。对于类似的非托管情况,请参阅 Raymond Chen 的文章When DLL_PROCESS_DETACH tells you that the process is exiting, your best bet is just to return without doing anything

建筑物正在拆除。不要费心打扫地面、清空垃圾箱和擦拭白板。

现在,有些人可能会提出这样的论点:你的一些可处理对象(disposables)可能代表着外部资源,当操作系统销毁您的进程时,这些资源将不会被清理/释放。虽然这是正确的,但这些外部资源必须应对例如用户终止进程或(如果不在同一台机器上)电源故障导致整台机器关闭等情况。当停电时,您无法运行任何清理代码。因此,它们已经被编写为可以处理您的进程无法释放资源的情况。

1
这里存在一些代码异味。
  1. StaticClass与其依赖的特定类型紧密耦合,而不是仅与接口耦合。
  2. StaticClass确定了它使用的服务的生命周期。
这会阻止StaticClass被彻底地单元测试。例如,您无法测试StaticClass的行为而不测试SomeDisposableType的行为。
我几乎总是建议将StaticClass变为非静态,并使用构造函数注入将其依赖的服务作为接口注入,从而允许依赖注入框架的配置决定这些对象的生命周期。
如果没有必要使StaticClass成为单例,则只需让它成为短暂的即可。您的DI框架应该负责清理注入到其中的可处理对象。
如果有一个强烈的理由使StaticClass成为单例,那么请认真考虑你的关注点分离:StaticClass是否做了太多的事情?例如,它可能会执行一些任务来查找值,然后存储这些值以避免以后再次执行该任务。或者它可能保存应用程序某些属性的状态,并根据该状态执行操作。在这些情况下,通常可以将状态保存或记忆/缓存工作分离到一个单独的类中,该类可以绑定为单例。然后,消耗此状态或缓存值的服务仍然可以是临时的,并且其可处置依赖项仍然可以在完成特定工作后被处置。
如果在考虑了上述所有内容之后,您仍然相信这个类需要具有长寿命,请仔细考虑您的可处置依赖项的寿命。通常,如果一个类是可处置的,那是因为它持有应该定期释放的资源。在这种情况下,也许您应该注入一个工厂,您可以使用它来按需构建服务,然后通过“using”语句在完成操作后立即处置它。
如果不知道更多关于您特定类的信息,很难提出更具体的建议,但这些是我发现在绝大多数情况下最有效的模式。

谢谢您对静态类的看法,但我不是在询问一个类是否应该是静态的,而是在询问静态类是否应该处理它的可处理静态成员。 - uncaged
1
@uncaged: 我能理解。经常被问的问题并不是真正需要回答的问题。如果有人问:“当瞄准自己的脚时,哪种握法最好”,虽然他们有可能有一个完全合理的理由来瞄准自己的脚,但除非他们提供更多信息,否则我的第一反应总是鼓励他们重新考虑这是否在第一时间就是个好主意。;-) 如果您已经决定在静态类中使用可丢弃成员,则可能无论何时或如何尝试处理它们都没有关系。 - StriplingWarrior

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接