【问题标题】:Will a C# class destructor be called when the class contains static fields?当类包含静态字段时,会调用 C# 类的析构函数吗?
【发布时间】:2017-06-12 07:51:47
【问题描述】:

在以下代码中:

public sealed class Switch
{
    public static MyObj s_object = new MyObj();
    private readonly SomeObject m_object = new SomeObject();

    ~Switch()
    {
        m_object?.Dispose();
    }
}

public class Test()
{
    Test() 
    {
        Switch switch = new Switch();
        switch = null;
        ...
    }
}

当 Test ctor 执行时,会创建一个新的 Switch 对象,然后立即将其设置为 null。在某些时候,GC 会处理它,在此过程中调用 ~Switch() 析构函数。但是当一个类包含像s_object 这样的静态字段并且调用应用程序没有终止(应用程序域仍然加载)时,会发生这种情况吗?静态对象在应用程序的生命周期内持续存在;这是否意味着包含它的非静态类也会?

【问题讨论】:

  • 我不知道这是否适用于你的情况,但一般你应该自己实现IDisposable来清理资源,并且只有在有非托管的东西需要清理时才使用析构函数。跨度>
  • @C.Evenhuis C# 甚至没有析构函数,它有完成不同工作的终结器
  • @C.Evenhuis 考虑到我们可以看到终结器的定义,我们实际上可以看到没有非托管资源,因此应该没有终结器,而是应该实现IDisposalbe
  • @DiskCrasher 我希望它确实如此(如果可能通过一些间接层),但如果感觉它是,它负责在终结器中清理它们值得。 MyObj 本身是一个托管对象(即使它包含非托管资源),因此,您根本不应该在终结器中访问它。
  • @DiskCrasher 如果它是一个类,它就是一个托管对象。非托管对象类似于文件句柄、网络套接字等。Socket 类是一个 托管 对象,负责管理 非托管 资源(实际操作系统插座)。处理一个类总是 100% 的时间,一个托管操作,你不应该在终结器中这样做。比如说,一个非托管资源会调用一个 OS 钩子来告诉它你不再需要一个套接字并且它应该被关闭(这就是 Socket 类在 its 中所做的事情终结器)。

标签: c# static finalizer


【解决方案1】:

这应该不是问题。就内存表示而言,静态字段与定义类型的实例不相关。

查看此帖子了解更多详细信息:How exactly do static fields work internally?

【讨论】:

    【解决方案2】:

    静态字段的存在对对象被垃圾收集(并因此最终确定)的时间没有影响。实例将在与没有静态字段的情况下发生的时间相当的时刻完成。

    静态字段对实例的唯一影响是静态初始化发生在第一个实例创建之前,因此可能会使第一个实例的创建速度比其他实例慢。

    注意:帖子中的代码显示了终结器的无效实现,因为它引用了其他托管对象并尝试对其调用方法。它导致两种情况下的未定义行为(有/没有静态字段)。

    【讨论】:

    • 问题是当一个类包含静态内容时是否会被释放,而不是时间问题(这意味着它可以)。
    • @DiskCrasher 我想我完全误读了你的问题 - 我读到“如果有静态字段,是否会在不同时间(或根本)调用 `~Switch()` 终结器”和通过声明静态字段不会改变调用终结器的时间来回答这个问题(因此,如果调用在没有静态字段的情况下发生,它将在类中有静态字段的可比时间发生)。但你真正的问题似乎是关于实际处置 - 而不是基于 m_object 的帖子处置中的代码在这两种情况下都将是未定义的(如果其他对象在终结器中未定义)
    猜你喜欢
    • 2012-09-02
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多