0

以下は、典型的な IDispose の実装です。私が理解していないのはデストラクタですか?クラスのユーザーが Dispose を呼び出すのを忘れた場合、デストラクタが r1.Dispose() を呼び出さないため、リソース リークが発生しませんか?

public class DisposableObject : IDisposable
    {
        private bool disposed;
        private UnmanagedResource r1;

        public DisposableObject()
        {
            r1 = new UnmanagedResource();
        }

        ~DisposableObject()
        {
            this.Dispose(false);
        }


        public void Dispose()
        {

             this.Dispose(true);
             GC.SuppressFinalize(this);       
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    // clean up managed resources
                    //call dispose on your member objects
                    r1.Dispose();
                }

                // clean up unmanaged resources
                this.disposed = true;
            }
        }

        public void SomeMethod()
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

        }
    }
4

6 に答える 6

2

いいえ - オブジェクトへのすべての参照がなくなると、GC はデストラクタを呼び出します (ただし、これは決定論的ではありません)。

于 2013-02-13T21:59:36.583 に答える
2

本当にネイティブ リソースである場合r1(この例ではそのようには見えません)、if(disposing) ブロック内ではなく、その後で破棄する必要があります。以下に特に注意してください。

if (disposing) 
{
    // free managed resources
    if (managedResource != null)
    {
        managedResource.Dispose();
        managedResource = null;
    }
}
// free native resources if there are any.
if (nativeResource != IntPtr.Zero) 
{
    Marshal.FreeHGlobal(nativeResource);
    nativeResource = IntPtr.Zero;
}

IDisposable を正しく実装することから- MSDN

r1が の独自の実装を持つ管理対象リソースである場合IDisposable、それが適切に実装されていると仮定すると、ネイティブ リソースはファイナライザーで適切にクリーンアップされます (これが、独自のリソースについて心配する必要がない理由です)。

于 2013-02-13T22:01:01.867 に答える
0

デストラクタ (ファイナライザ) が Dispose を呼び出す理由は、オブジェクトを収集する前にガベージ コレクタが Dispose を呼び出し、少なくともある時点で UnmanagedResource が解放されることを保証するためです。

usingandを使用try...finallyすることで、リソースが不要になったらすぐに破棄するよう強制できます。

http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx

于 2013-02-13T22:01:10.143 に答える
0

本当にしたい場合は、ファイナライザーを追加できます。

~DisposeImplementation()
{
    Dispose(false);
}

ただし、これは最後の手段としてのみ使用する必要があり、直接依存するものではありません。

于 2013-02-13T22:02:49.580 に答える
0

.Net には、ガベージ コレクションと呼ばれる機能があります。ガベージ コレクションは、(それ以上) 参照されていないすべてのオブジェクトをファイナライズします。次に、デストラクタ/ファイナライザが Dispose() を呼び出します。

ユーザーがこれらの参照を削除するのを忘れると、一種のリークが発生します。しかし、それusingが目的です:要件の範囲内でのみ使い捨てを定義することにより、メモリのブロックを回避します。

于 2013-02-13T22:04:10.870 に答える
0

このパターンが存在するのは、ガベージ コレクターがマネージド オブジェクトのガベージ コレクションの順序を保証していないためです。r1したがって、ファイナライザーでは、参照がまだ有効であることが保証されていません。

あなたのr1参照には のクラス名がありますUnmanagedResourceが、明らかにマネージド型です。IntPtr実際の無人リソースの場合、トークンまたはその他のトークンしかありません。r1リソースが気に入らないことを確認するには、同じ Dispose パターンを実装し、if (disposing)チェックの外で管理されていないリソースを解放する必要があります。

于 2013-02-13T22:04:12.537 に答える