it-swarm.com.de

IDisposable richtig implementieren

In meinen Klassen implementiere ich IDisposable wie folgt:

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

In VS2012 heißt es in meiner Codeanalyse, IDisposable korrekt zu implementieren, aber ich bin mir nicht sicher, was ich hier falsch gemacht habe.
Der genaue Text lautet wie folgt:

CAe1063 IDisposable korrekt implementieren Stellen Sie eine überschreibbare Implementierung von Dispose (bool) unter 'Benutzer' bereit, oder kennzeichnen Sie den Typ als versiegelt. Ein Aufruf an Dispose (false) sollte nur native Ressourcen bereinigen. Ein Aufruf an Dispose (true) sollte sowohl verwaltete als auch native Ressourcen bereinigen. stman User.cs 10

Für Referenz: CA1063: IDisposable korrekt implementieren

Ich habe diese Seite durchgelesen, aber ich verstehe nicht wirklich, was hier zu tun ist.

Wenn irgendjemand mehr Lamens erklären kann, was das Problem ist und/oder wie IDisposable implementiert werden sollte, wird das wirklich helfen!

119
Ortund

Dies wäre die korrekte Implementierung, obwohl ich in dem von Ihnen geposteten Code nichts zu sehen brauche. Sie müssen IDisposable nur implementieren, wenn:

  1. Sie haben nicht verwaltete Ressourcen
  2. Sie halten an Referenzen von Dingen fest, die selbst verfügbar sind.

Nichts in dem von Ihnen geposteten Code muss entsorgt werden.

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

}
94
Daniel Mann

Zunächst müssen Sie strings und ints nicht "bereinigen" - sie werden automatisch vom Speicherbereiniger erledigt. Das einzige, was in Dispose aufgeräumt werden muss, sind nicht verwaltete Ressourcen oder verwaltete Ressourcen, die IDisposable implementieren.

Unter der Annahme, dass dies nur eine Lernübung ist, besteht der empfohlene - Weg zur Implementierung von IDisposable darin, eine "Sicherheitslücke" hinzuzufügen, um sicherzustellen, dass Ressourcen nicht zweimal entsorgt werden:

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;   
    }
}
52
D Stanley

Das folgende Beispiel zeigt die allgemeine bewährte Vorgehensweise zum Implementieren der IDisposable-Schnittstelle. Referenz

Denken Sie daran, dass Sie einen Destruktor (Finalizer) nur benötigen, wenn Ihre Klasse über nicht verwaltete Ressourcen verfügt. Wenn Sie einen Destruktor hinzufügen, sollten Sie Finalization in Dispose unterdrücken. Andernfalls werden Ihre Objekte für zwei Müllzyklen im Speicher gespeichert (Hinweis: Lesen Sie, wie Finalization funktioniert ). Im folgenden Beispiel werden alle oben ausgeführt.

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

IDisposable bietet Ihnen die Möglichkeit, bereinigte nicht verwaltete Ressourcen zu bereinigen, die vom Garbage Collector nicht automatisch bereinigt werden.

Alle Ressourcen, die Sie "bereinigen", sind verwaltete Ressourcen, und als solche führt Ihre Dispose-Methode nichts aus. Ihre Klasse sollte IDisposable überhaupt nicht implementieren. Der Müllsammler wird sich um alle diese Felder kümmern.

13
Servy

Sie müssen das Disposable Pattern wie folgt verwenden:

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

Sie müssen Ihre User-Klasse nicht als IDisposable definieren, da die Klasse nicht erworben nicht verwaltete Ressourcen (Datei, Datenbankverbindung usw.) verwendet. Normalerweise kennzeichnen wir Klassen als IDisposable, wenn sie mindestens ein IDisposable Feld oder/und eine Eigenschaft haben. Wenn Sie IDisposable implementieren, setzen Sie es besser gemäß dem typischen Microsoft-Schema ein:

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

Idisposable ist zu implementieren, wann immer Sie eine deterministische (bestätigte) Garbage Collection benötigen.

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

Verwenden Sie beim Erstellen und Verwenden der Users-Klasse den using-Block, um das explizite Aufrufen der dispose-Methode zu vermeiden: 

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

ende des Verwendungsblocks erstelltes Benutzerobjekt wird durch impliziten Aufruf der dispose-Methode gelöscht.

3
S.Roshanth

IDisposable implementiert für die Garbage Collection.ID implementiert die Dispose-Methode, die implizit vom Finalizer-Thread aufgerufen wird.

internal class ConnectionConfiguration : IDisposable
{
    private static volatile IConnection _masterconnection;
    private static readonly object ConnectionLock = new object();
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
        if (_masterconnection == null)
        {
            return;
        }
        lock (ConnectionLock)
        {
            if (_masterconnection == null)
            {
                return;
            }
            _masterconnection?.Dispose();//double check
            _masterconnection = null;
        }
    }
}
0

Ich sehe viele Beispiele für das Microsoft Dispose-Muster, bei dem es sich tatsächlich um ein Anti-Muster handelt. Wie viele darauf hingewiesen haben, erfordert der Code in der Frage überhaupt keine IDisposable. Wenn Sie es implementieren möchten, verwenden Sie bitte nicht das Microsoft-Muster. Eine bessere Antwort wäre, wenn Sie die Vorschläge in diesem Artikel befolgen:

https://www.codeproject.com/Articles/29534/IDisposable-Was-Ihre-Mutter-Never-Told-You-Über -

Die einzige andere Sache, die wahrscheinlich hilfreich sein könnte, ist die Unterdrückung der Warnung vor der Codeanalyse ... https://docs.Microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view= vs-2017

0
MikeJ