164

私のクラスでは、次のように実装IDisposableします。

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int UserID)
    {
        id = UserID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

    public void Dispose()
    {
        // Clear all property values that maybe have been set
        // when the class was instantiated
        id = 0;
        name = String.Empty;
        pass = String.Empty;
    }
}

VS2012 では、コード分析で IDisposable を正しく実装するように指示されていますが、ここで何が間違っていたのかわかりません。
正確なテキストは次のとおりです。

CA1063 IDisposable を正しく実装します 'User' で Dispose(bool) のオーバーライド可能な実装を提供するか、タイプをシール済みとしてマークします。Dispose(false) の呼び出しは、ネイティブ リソースのみをクリーンアップする必要があります。Dispose(true) を呼び出すと、マネージ リソースとネイティブ リソースの両方がクリーンアップされます。stman User.cs 10

参考: CA1063: IDisposable を正しく実装する

このページを読みましたが、ここで何をする必要があるのか​​ よくわかりません。

問題が何であるか、および/またはどのIDisposableように実装する必要があるかをより素人の言葉で説明できる人がいれば、それは本当に役に立ちます!

4

8 に答える 8

132

これは正しい実装ですが、投稿したコードで処分する必要があるものは何もありません。次の場合にのみ実装する必要がありますIDisposable

  1. 管理されていないリソースがあります
  2. それ自体が使い捨てであるものの参照を保持しています。

投稿したコードの何も破棄する必要はありません。

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int userID)
    {
        id = userID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources if there are any.
    }
}
于 2013-08-20T13:59:48.317 に答える
65

まず第一に、 と を「クリーンアップ」する必要はありませんstringintこれらはガベージ コレクタによって自動的に処理されます。クリーンアップする必要があるのDisposeは、アンマネージド リソースまたは を実装するマネージド リソースだけIDisposableです。

ただし、これは単なる学習課題であると仮定すると、推奨される実装方法IDisposableは、「セーフティ キャッチ」を追加して、リソースが 2 回破棄されないようにすることです。

public void Dispose()
{
    Dispose(true);

    // Use SupressFinalize in case a subclass 
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);   
}
protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing) 
        {
            // Clear all property values that maybe have been set
            // when the class was instantiated
            id = 0;
            name = String.Empty;
            pass = String.Empty;
        }

        // Indicate that the instance has been disposed.
        _disposed = true;   
    }
}
于 2013-08-20T13:59:08.290 に答える
47

次の例は、インターフェイスを実装するための一般的なベスト プラクティスを示していIDisposableます。参照

クラスに管理されていないリソースがある場合にのみ、デストラクタ (ファイナライザ) が必要になることに注意してください。また、デストラクタを追加する場合は、 Disposeで Finalization を抑制する必要があります。そうしないと、オブジェクトが 2 つのガベージ サイクルの間メモリ内に存在することになります (注: Finalization の仕組みを読んでください)。以下の例では、上記のすべてを詳しく説明しています。

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}
于 2015-06-24T03:10:16.107 に答える
14

次のように使い捨てパターンを使用する必要があります。

private bool _disposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            // Dispose any managed objects
            // ...
        }

        // Now disposed of any unmanaged objects
        // ...

        _disposed = true;
    }
}

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

// Destructor
~YourClassName()
{
    Dispose(false);
}
于 2013-08-20T13:59:09.417 に答える
14

IDisposableガベージ コレクターによって自動的にクリーンアップされないアンマネージドリソースをクリーンアップする手段を提供するために存在します。

「クリーンアップ」しているすべてのリソースは管理されたリソースであるため、Disposeメソッドは何も達成していません。あなたのクラスはまったく実装すべきではありませんIDisposable。ガベージ コレクターは、これらすべてのフィールドを単独で問題なく処理します。

于 2013-08-20T13:58:54.487 に答える
3

Idisposable は、確定的な (確認済みの) ガベージ コレクションが必要な場合にいつでも実装されます。

class Users : IDisposable
    {
        ~Users()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            // This method will remove current object from garbage collector's queue 
            // and stop calling finilize method twice 
        }    

        public void Dispose(bool disposer)
        {
            if (disposer)
            {
                // dispose the managed objects
            }
            // dispose the unmanaged objects
        }
    }

Users クラスを作成して使用するときは、「using」ブロックを使用して、dispose メソッドを明示的に呼び出さないようにします。

using (Users _user = new Users())
            {
                // do user related work
            }

using ブロックの最後に作成された Users オブジェクトは、dispose メソッドの暗黙的な呼び出しによって破棄されます。

于 2014-09-29T12:19:10.547 に答える