在Dispose()中设置obj = null(Nothing)的意义吗?

时间:2010-02-17 11:06:08

标签: c# .net vb.net memory-management dispose

null方法中将自定义对象设置为Nothing(VB.NET中为Dispose())是否有意义? 这可以防止内存泄漏或无用吗?!

让我们考虑两个例子:

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?
        }
    }
}

8 个答案:

答案 0 :(得分:24)

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

  • 这意味着如果有人忘记释放Foo(可能来自某个事件),任何下游对象(在这种情况下为Bitmap)仍然可以被收集(在未来的某个时刻 - 每当GC感觉像这样); 可能这只是一个围绕非托管资源的浅层包装器,但每一点都有帮助。
    • 真的不喜欢因为用户忘记解开一个事件而意外地保持整个对象图形。 IDisposable是一个方便的“几乎杀死”开关 - 为什么不分离所有可用的东西?
  • 更重要的是,我现在可以诙谐地使用此字段来检查(在方法等中)进行处置,如果是ObjectDisposedException则抛出null

答案 1 :(得分:20)

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

例外情况是,如果您希望调用者在此之后调用Dispose 保留实例。在这种情况下,将内部引用设置为null是个好主意。然而,一次性实例通常同时被丢弃和释放。在这些情况下,它不会产生很大的不同。

答案 2 :(得分:4)

这只是无用的。我认为,在旧的COM / VB天中设置为NULL会减少您的引用计数。

.NET不适用。将bar设置为null时,不会破坏或释放任何内容。您只是将条指向的引用从您的对象更改为“null”。你的对象仍然存在(虽然现在,因为没有任何引用它,它最终将被垃圾收集)。除了极少数例外情况,在大多数情况下,如果您没有首先制作Foo IDisposable,就会发生同样的情况。

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

答案 3 :(得分:1)

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

如果将对一次性字段的引用设置为null,则可以保证不再使用这些实例。

使用自有的已处置实例不会导致ObjectDisposedException或任何其他无效状态(如果不检查空值,则可能会获得NullReferenceException)。

只要所有IDisposable对象具有IsDisposed属性和/或抛出ObjectDisposedException(如果在处置后使用它们),这可能对您没有意义 - 有些可能违反此原则并将它们设置为null可以防止发生不必要的影响。

答案 4 :(得分:1)

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

因此,理论上最好在C#中的Dispose-Method中释放对托管对象的引用,但仅限于GC在收集已处置对象之前收集引用对象的可能性。由于两者最有可能在同一次运行中收集,因此GC最可能会认识到,引用的对象仅由处置类型引用,因此两者都可以被收集。

此外,释放引用的需求非常小,因为如果同时处理该类,则您的一次性类的所有公共成员都应该抛出异常。因此,在处理引用的方法后,无法访问引用的对象。

答案 5 :(得分:1)

VB.NET 有意义设置为Nothing声明的 Private WithEvents 对象。

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

答案 6 :(得分:0)

dispose()的目的是清理不受管理的资源。开发人员应该在dispose方法中释放TCP连接,数据库连接和其他数据库对象以及大量此类非托管资源。所以它真的很有意义。

答案 7 :(得分:0)

一般不需要设置为null。但是假设你的课程中有一个重置功能。<​​/ p>

然后你可能会这样做,因为你不想两次调用dispose,因为某些Dispose可能无法正确实现并抛出System.ObjectDisposed异常。

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }