Implementando IDisposable correctamente

En mis clases implemento IDisposable de la siguiente manera:

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

En VS2012, mi análisis de código dice que debo implementar IDisposable correctamente, pero no estoy seguro de lo que he hecho mal aquí.
El texto exacto es el siguiente:

CA1063 Implemento IDisposable correctamente Proporcione una implementación sobresaliente de Dispose (bool) en ‘User’ o marque el tipo como sellado. Una llamada a Dispose (false) solo debería limpiar los recursos nativos. Una llamada a Deshacer (verdadero) debe limpiar los recursos nativos y administrados. stman User.cs 10

Para referencia: CA1063: Implementar IDisposable correctamente

He leído esta página, pero me temo que realmente no entiendo lo que hay que hacer aquí.

Si alguien puede explicar en términos más lamen cuál es el problema y cómo se debe implementar IDisposable, ¡eso realmente ayudará!

    Esta sería la implementación correcta, aunque no veo nada que deba eliminar en el código que publicó. Solo necesita implementar IDisposable cuando:

    1. Tienes recursos no administrados
    2. Estás aferrado a referencias de cosas que son desechables.

    Nada en el código que ha publicado debe eliminarse.

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

    En primer lugar, no es necesario que “limpie” string e int . – el recolector de basura se encargará de ellos automáticamente. Lo único que debe limpiarse en Dispose son los recursos no gestionados o los recursos gestionados que implementan IDisposable .

    Sin embargo, suponiendo que esto sea solo un ejercicio de aprendizaje, la forma recomendada de implementar IDisposable es agregar una “captura de seguridad” para garantizar que los recursos no se eliminen dos veces:

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

    El siguiente ejemplo muestra las mejores prácticas generales para implementar la interfaz IDisposable . Referencia

    Tenga en cuenta que necesita un destructor (finalizador) solo si tiene recursos no administrados en su clase. Y si agrega un destructor, debe suprimir la Finalización en el Dispose , de lo contrario causará que sus objetos residan en la memoria durante dos ciclos de basura (Nota: lea cómo funciona la Finalización ). Más abajo, ejemplifica todo lo anterior.

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

    IDisposable existe para proporcionarle un medio de limpiar recursos no administrados que no serán limpiados automáticamente por el recolector de basura.

    Todos los recursos que está “limpiando” son recursos administrados, y como tal, su método Dispose está logrando nada. Tu clase no debería implementar IDisposable en absoluto. The Garbage Collector se encargará de todos esos campos por sí solo.

    Necesitas usar el Patrón Desechable de esta manera:

     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); } 

    No es necesario que su clase de usuario sea identificable ya que la clase no adquiere ningún recurso no administrado (archivo, conexión de base de datos, etc.). Por lo general, marcamos las clases como IDisposable si tienen al menos un campo y / o propiedad IDisposable. Al implementar IDisposable, mejor ponlo según el esquema típico de Microsoft:

     public class User: IDisposable { ... protected virtual void Dispose(Boolean disposing) { if (disposing) { // There's no need to set zero empty values to fields // id = 0; // name = String.Empty; // pass = String.Empty; //TODO: free your true resources here (usually IDisposable fields) } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

    Idisposable es implementar siempre que quieras una recolección de basura determinista (confirmada).

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

    Al crear y utilizar la clase Users, use el bloque “using” para evitar el método de invocación explícitamente:

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

    el final del objeto Usuario creado del bloque de uso se eliminará mediante el método de invocación de disposición implícita.