在析构函数中处置对象

问题描述 投票:0回答:7

我有一个对象,其中包含一次性对象作为成员。

public class MyClass
{
    private MyDisposableMember member;

    public DoSomething
    {
         using (member = new MyDisposableMember())
         {
             // Blah...
         }
    }
}

MyClass
中可以有很多方法,所有方法都需要
using
语句。但如果我这样做呢?

public class MyClass
{
    private MyDisposableMember member = new MyDisposableMember();

    public DoSomething
    {
         // Do things with member :)
    }

    ~MyClass()
    {
        member.Dispose();
    }
}

如您所见,

member
正在析构函数中被处置。这行得通吗?这种方法有什么问题吗?

c# dispose idisposable
7个回答
11
投票

理想情况下,Dispose() 应该在最终确定之前被调用。最好遵循典型的 dispose 模式,并允许用户正确 Dispose() 对象,并让终结器对其进行 Dispose 如果 dispose 尚未被调用

在这种情况下,由于您封装了 IDisposable,因此您实际上根本不需要实现终结器。 (在最终确定时,您的封装成员将被最终确定,因此无需最终确定您的对象 - 它只会增加开销。)有关详细信息,请阅读我写的关于封装 IDisposable 的博客文章


8
投票
您可能应该让

MyClass

 实现 
IDisposable
。在 
Dispose()
 方法内,调用 
member.Dispose();
。这样程序员就可以控制成员何时被处置。


3
投票
不要这样做!

GC 将为您执行此操作(间接作为要处置的对象或另一个对象将包含析构函数)

MyDisposableMember 甚至可能在您处置它之前就被 GC 处置 - 然后发生的事情可能不是您想要做的。

更糟糕的是:在类中添加析构函数(或终结器)会在处理对象时花费额外的时间(因为对象将在内存中保留至少一个收集周期,甚至可能提升到下一代),因此会花费更多时间。

那么,就完全没有用,甚至适得其反。


1
投票
在您的第一个示例中,成员实际上并不是对象状态的一部分,因为您每次使用它时都会实例化它并在之后立即处置它。由于它不是状态的一部分,因此不要对其进行建模,只需在需要时使用局部变量即可。

更一般地说,您应该将所有处理逻辑放在 Dispose() 中并实现 IDisposable,然后将您的类与 using 或 try-finally 一起使用


0
投票
我认为唯一错误(而且不是错误)的是,在 using 语句中,您在该时间点(当您的函数/方法被调用时)显式地处置了该对象。析构函数不能被调用,它们会被自动调用。所以此时可能需要一段时间才能处理掉会员。最好为 MyClass 实现 IDisposeable 接口。


0
投票
遵循 Microsoft 模式是您最好的选择,以便您班级的用户可以完全控制何时处理它。

public class MyClass : IDisposable { private MyDisposableMember member = new MyDisposableMember(); public DoSomething { // Do things with member :) } ~MyClass() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) // Release managed resources { member.Dispose(); } // Release unmanaged resources } }
    

0
投票
当终结器运行时,对于它持有引用的几乎所有

IDisposable

 对象,以下任一情况都成立:

  1. 该对象将已经运行其终结器,在这种情况下,在该对象上调用

    Dispose

     至多是无用的。

  2. 该对象不会运行其终结器,但其终结器将被安排运行,因此在该对象上调用

    Dispose

     将毫无用处。

  3. 该对象仍将被正在最终确定的对象以外的其他对象使用,因此对其调用

    Dispose

     会很糟糕。

在某些情况下,在终结器中调用

Dispose

 可能会很有用,但大多数情况都符合上面列出的情况,这些情况都有一个共同的特征:终结器不应调用 
Dispose

© www.soinside.com 2019 - 2024. All rights reserved.