Implémenter IDisposable correctement

Dans mes cours, j’implémente IDisposable comme suit:

public class User : IDisposable { public int id { get; protected set; } public ssortingng name { get; protected set; } public ssortingng pass { get; protected set; } public User(int UserID) { id = UserID; } public User(ssortingng Username, ssortingng 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 = Ssortingng.Empty; pass = Ssortingng.Empty; } } 

Dans VS2012, mon parsing de code dit de mettre en œuvre correctement IDisposable, mais je ne suis pas sûr de ce que j’ai fait de mal ici.
Le texte exact est le suivant:

CA1063 Implémenter correctement IDisposable Fournit une implémentation remplaçable de Dispose (bool) sur «Utilisateur» ou marque le type comme étant scellé. Un appel à Dispose (false) ne doit nettoyer que les ressources natives. Un appel à Dispose (true) devrait nettoyer les ressources gérées et les ressources natives. stman User.cs 10

Pour référence: CA1063: implémenter IDisposable correctement

J’ai lu cette page, mais j’ai bien peur de ne pas vraiment comprendre ce qui doit être fait ici.

Si quelqu’un peut expliquer, en d’autres termes, quel est le problème et / ou comment mettre en œuvre IDisposable, cela aidera vraiment!

    Ce serait l’implémentation correcte, même si je ne vois rien à éliminer dans le code que vous avez posté. Vous devez uniquement implémenter IDisposable lorsque:

    1. Vous avez des ressources non gérées
    2. Vous vous attachez à des références de choses qui sont elles-mêmes jetables.

    Rien dans le code que vous avez posté ne doit être supprimé.

     public class User : IDisposable { public int id { get; protected set; } public ssortingng name { get; protected set; } public ssortingng pass { get; protected set; } public User(int userID) { id = userID; } public User(ssortingng Username, ssortingng 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. } } 

    Tout d’abord, vous n’avez pas besoin de “nettoyer” les ssortingng s et int s – elles seront automatiquement sockets en charge par le ramasse-miettes. La seule chose à nettoyer dans Dispose sont les ressources non gérées ou les ressources gérées qui implémentent IDisposable .

    Cependant, en supposant qu’il ne s’agisse que d’un exercice d’apprentissage, la méthode recommandée pour implémenter IDisposable consiste à append un “verrou de sécurité” pour garantir que toutes les ressources ne sont pas supprimées deux fois:

     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 = Ssortingng.Empty; pass = Ssortingng.Empty; } // Indicate that the instance has been disposed. _disposed = true; } } 

    L’exemple suivant montre la meilleure pratique générale pour implémenter une interface IDisposable . Référence

    Gardez à l’esprit que vous avez besoin d’un destructeur (finalizer) uniquement si vous avez des ressources non gérées dans votre classe. Et si vous ajoutez un destructeur, vous devez supprimer la Finalisation dans Dispose , sinon vos objects restront en mémoire pour deux cycles de nettoyage (Remarque: lisez comment fonctionne la Finalisation ). L’exemple ci-dessous élabore tout ce qui précède.

     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 pour vous permettre de nettoyer les ressources non gérées qui ne seront pas nettoyées automatiquement par le garbage collector.

    Toutes les ressources que vous «nettoyez» sont des ressources gérées et, par conséquent, votre méthode Dispose ne fait rien. Votre classe ne doit pas du tout implémenter IDisposable . Le ramasse-miettes s’occupera de tous ces champs tout seul.

    Vous devez utiliser le modèle jetable comme ceci:

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

    Vous n’avez pas besoin de faire que votre classe d’utilisateur soit IDisposable car la classe n’acquiert aucune ressource non gérée (fichier, connexion à la firebase database, etc.). Habituellement, nous marquons les classes comme IDisposable si elles ont au moins un champ ou une propriété IDisposable. Lors de la mise en œuvre d’IDisposable, mieux vaut le mettre selon le schéma standard 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 = Ssortingng.Empty; // pass = Ssortingng.Empty; //TODO: free your true resources here (usually IDisposable fields) } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

    Idisposable est implémentable à chaque fois que vous voulez un nettoyage de la mémoire déterministe (confirmé).

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

    Lors de la création et de l’utilisation de la classe Users, utilisez le bloc “using” pour éviter d’appeler explicitement la méthode dispose:

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

    la fin du bloc using créé L’object Users sera éliminé par la méthode implicite invoke of dispose.