关于c#:在Dispose()中设置obj = null(Nothing)的意义?

Any sense to set obj = null(Nothing) in Dispose()?

Dispose()方法中,是否有必要将自定义对象设置为null(vb.net中的Nothing?这能防止内存泄漏吗?还是没用?!

让我们考虑两个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Foo : IDisposable
{
    private Bar bar; // standard custom .NET object

    public Foo(Bar bar) {
        this.bar = bar;
    }
    public void Dispose() {
        bar = null; // any sense?
    }
}

public class Foo : RichTextBox
{
    // this could be also: GDI+, TCP socket, SQl Connection, other"heavy" object
    private Bitmap backImage;

    public Foo(Bitmap backImage) {
        this.backImage = backImage;
    }

    protected override void Dispose(bool disposing) {
        if (disposing) {
            backImage = null;  // any sense?
        }
    }
}

我个人倾向于;有两个原因:

    百万千克1这意味着,如果有人忘记释放Foo(可能来自某个事件),任何下游对象(在本例中为Bitmap)仍然可以被收集(在将来的某个时候,无论何时GC感觉到);这很可能只是围绕非托管资源的一个浅薄的包装,但几乎没有什么帮助。

      百万千克1我真的不喜欢仅仅因为用户忘记解开一个事件就意外地挂起一个完整的对象图;IDisposable是一个方便的"几乎杀死"的开关——为什么不拆开所有可用的东西呢?百万千克1

    型百万千克1百万千克1更重要的是,我现在可以冒失地使用这个字段检查(方法等)处理,如果是null,则抛出ObjectDisposedException。百万千克1


Dispose()的目的是允许清理垃圾收集器未处理的资源。对象由GC负责,因此在正常情况下,实际上不需要将引用设置为空。

例外情况是,如果您希望调用者调用Dispose,并在调用后保留实例。在这种情况下,最好将内部引用设置为空。但是,可释放实例通常是同时释放和释放的。在这些情况下,这不会有很大的区别。


只是没用而已。我相信,在旧的com/vb天设置为空将减少引用计数。

在.NET中不是这样的。当您将BAR设置为空时,不会破坏或释放任何内容。您只是将条指向的引用从对象更改为"空"。您的对象仍然存在(尽管现在没有引用它,但它最终将被垃圾收集)。除了少数例外,在大多数情况下,如果你一开始就不让foo idisposable的话,这也是会发生的事情。

IDisposable的主要目的是允许您释放非托管资源,如TCP套接字或SQL连接,或其他任何资源。这通常是通过调用非托管资源提供的任何清理函数来完成的,而不是通过将引用设置为"null"。


在vb.net中,有必要设置为Nothing声明的Private WithEvents对象。

使用Handles关键字的处理程序将以这种方式从这些对象中删除。


在C中,将对象设置为空只是释放对该对象的引用。

因此,理论上最好在C中释放Dispose方法中对托管对象的引用,但仅限于GC在收集已释放对象之前收集被引用对象的可能性。由于这两个对象很可能在同一个运行中被收集,所以GC将最恰当地认识到,被引用的对象仅由已释放的类型引用,因此可以同时收集这两个对象。

另外,释放引用的需求也很小,因为如果类已经被释放,可释放类的所有公共成员都应该抛出一个异常。因此,在释放被引用的方法之后,对被引用对象的任何访问都不会成功。


如果您想以某种方式阻止重新使用释放的拥有的实例,这是有意义的。

当您将对可释放字段的引用设置为空时,将保证不再使用这些实例。

您不会得到ObjectDisposedException或任何其他由于使用所拥有的释放实例而导致的无效状态(如果不检查空值,您可以得到NullReferenceException)。

只要所有IDisposable对象都具有IsDisposed属性和/或如果在处置后使用ObjectDisposedException对象,这可能对您没有意义,有些对象可能违反此原则,将其设为空可能会防止产生不必要的影响。


通常不需要设置为空。但是假设您的类中有一个重置功能。

然后您可能会这样做,因为您不希望调用Dispose两次,因为某些Dispose可能无法正确实现,并引发System.ObjectDisposed异常。

1
2
3
4
5
6
7
8
9
private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }

Dispose()的目的是清除未管理的资源。TCP连接、数据库连接和其他数据库对象以及许多此类非托管资源应该由开发人员在Dispose方法中释放。所以这很有道理。