在终结器中访问引用类型成员变量是否安全?

Can*_*ith 9 .net finalizer

换一种说法,

class Foo
{
    object obj;
    Foo() { obj = new object(); }
    ~Foo() { obj.ToString(); /* NullReferenceException? */ }
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*ner 7

来自Object.Finalize:

两个对象的终结器不保证以任何特定顺序运行,即使一个对象引用另一个对象.也就是说,如果对象A具有对象B的引用并且两者都具有终结器,则当对象A的终结器开始时,对象B可能已经完成.

简而言之,您不能在终结器期间对引用对象的状态做出任何假设.

几乎在所有情况下,终结器中实现的逻辑都属于Disposable模式.这是如何使用IDisposable接口在.NET中正确实现模式的示例.

public class MyClass : IDisposable
{
    private bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if(disposing)
            {
                // Release unmanaged resources.
            }

            // Release managed resources (Streams, SqlConnections, etc.)
        }

        _disposed = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您正在使用非托管资源,请查看本文以了解如何IDisposable使用终结器实现:

MDSN:实现完成和处理以清理非托管资源

  • 仅仅因为你实现`IDisposable`确实*不*意味着你应该实现终结器.实际上,您几乎从不想实现终结器.但是,如果你实现了终结器,你还应该实现`IDisposable`. (3认同)

stm*_*max 7

这不安全,因为obj可能已经被垃圾收集了.另请注意,垃圾收集器不会将引用设置为null.因此,即使检查obj!= null也无济于事.

详情请见:http: //msdn.microsoft.com/en-us/magazine/cc163392.aspx#S3

" 概括这个原则,在Dispose方法中,清除对象所持有的所有资源是安全的,无论它们是托管对象还是本机资源.但是,在终结器中清理不可最终化的对象是安全的,并且通常终结器应该只释放本机资源. "(你的obj是最终的,所以你不应该在另一个终结器中触摸它)

这也是你拥有的原因

如果(处置){...}

在IDisposable模式中(参见上面链接中的图2).

  • 所以答案是:*如果*您*确定*知道引用的对象也被其他活动对象引用,那么它是安全的。 (2认同)