416 Stimmen

Verwendung der Finalize/Dispose-Methode in C#

C# 2008

Ich arbeite jetzt schon eine Weile daran und bin immer noch verwirrt über die Verwendung von Finalize- und Dispose-Methoden im Code. Meine Fragen sind unten:

  1. Ich weiß, dass wir nur einen Finalizer benötigen, wenn wir nicht verwaltete Ressourcen entsorgen. Wenn es jedoch verwaltete Ressourcen gibt, die Aufrufe an nicht verwaltete Ressourcen tätigen, müsste dann immer noch ein Finalizer implementiert werden?

  2. Wenn ich jedoch eine Klasse entwickle, die keine nicht verwaltete Ressource - direkt oder indirekt - verwendet, sollte ich die IDisposable damit die Clients dieser Klasse die "using-Anweisung" verwenden können?

    Wäre es machbar, IDisposable zu implementieren, nur um den Clients Ihrer Klasse die Verwendung der using-Anweisung zu ermöglichen?

    using(myClass objClass = new myClass())
    {
        // Do stuff here
    }
  3. Ich habe den folgenden einfachen Code entwickelt, um die Verwendung von Finalize/Dispose zu demonstrieren:

    public class NoGateway : IDisposable
    {
        private WebClient wc = null;
    
        public NoGateway()
        {
            wc = new WebClient();
            wc.DownloadStringCompleted += wc_DownloadStringCompleted;
        }
    
        // Start the Async call to find if NoGateway is true or false
        public void NoGatewayStatus()
        {
            // Start the Async's download
                // Do other work here
            wc.DownloadStringAsync(new Uri(www.xxxx.xxx));
        }
    
        private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // Do work here
        }
    
        // Dispose of the NoGateway object
        public void Dispose()
        {
            wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
            wc.Dispose();
            GC.SuppressFinalize(this);
        }
    }

Frage zum Quellcode:

  1. Hier habe ich den Finalizer nicht hinzugefügt, und normalerweise wird der Finalizer vom GC aufgerufen, und der Finalizer ruft den Dispose auf. Da ich den Finalizer nicht habe, wann rufe ich die Dispose-Methode auf? Ist es der Client der Klasse, der sie aufrufen muss?

    Meine Klasse im Beispiel heißt also NoGateway und der Client könnte die Klasse wie folgt verwenden und entsorgen:

    using(NoGateway objNoGateway = new NoGateway())
    {
        // Do stuff here   
    }

    Wird die Dispose-Methode automatisch aufgerufen, wenn die Ausführung das Ende des using-Blocks erreicht, oder muss der Client die Dispose-Methode manuell aufrufen? d.h.

    NoGateway objNoGateway = new NoGateway();
    // Do stuff with object
    objNoGateway.Dispose(); // finished with it
  2. Ich verwende die WebClient Klasse in meinem NoGateway Klasse. Denn WebClient implementiert die IDisposable Schnittstelle, bedeutet dies, dass WebClient indirekt nicht verwaltete Ressourcen verwendet? Gibt es eine feste Regel, um dies zu befolgen? Woher weiß ich, dass eine Klasse nicht verwaltete Ressourcen verwendet?

2voto

softwarematter Punkte 26522

Muster von msdn

public class BaseResource: IDisposable
{
   private IntPtr handle;
   private Component Components;
   private bool disposed = false;
   public BaseResource()
   {
   }
   public void Dispose()
   {
      Dispose(true);      
      GC.SuppressFinalize(this);
   }
   protected virtual void Dispose(bool disposing)
   {
      if(!this.disposed)
      {        
         if(disposing)
         {
            Components.Dispose();
         }         
         CloseHandle(handle);
         handle = IntPtr.Zero;
       }
      disposed = true;         
   }
   ~BaseResource()      
   {      Dispose(false);
   }
   public void DoSomething()
   {
      if(this.disposed)
      {
         throw new ObjectDisposedException();
      }
   }
}
public class MyResourceWrapper: BaseResource
{
   private ManagedResource addedManaged;
   private NativeResource addedNative;
   private bool disposed = false;
   public MyResourceWrapper()
   {
   }
   protected override void Dispose(bool disposing)
   {
      if(!this.disposed)
      {
         try
         {
            if(disposing)
            {             
               addedManaged.Dispose();         
            }
            CloseHandle(addedNative);
            this.disposed = true;
         }
         finally
         {
            base.Dispose(disposing);
         }
      }
   }
}

1voto

Daniel Fabian Punkte 3778
using(NoGateway objNoGateway = new NoGateway())

ist gleichbedeutend mit

try
{
    NoGateway = new NoGateway();
}

finally
{
    NoGateway.Dispose();
}

Ein Finalizer wird aufgerufen, wenn der GC Ihr Objekt zerstört. Dies kann zu einem völlig anderen Zeitpunkt geschehen, als wenn Sie Ihre Methode verlassen. Das Dispose von IDisposable wird unmittelbar nach Verlassen des using-Blocks aufgerufen. Daher ist das Muster normalerweise, using zu verwenden, um Ressourcen sofort freizugeben, nachdem man sie nicht mehr benötigt.

-5voto

Nic Wise Punkte 7791

Soweit ich weiß, wird dringend empfohlen, den Finalizer / Destructor nicht zu verwenden:

public ~MyClass() {
  //dont use this
}

Meistens liegt das daran, dass man nicht weiß, wann oder ob sie aufgerufen wird. Die Dispose-Methode ist viel besser, vor allem, wenn Sie mit oder direkt entsorgen.

Verwenden ist gut. Verwenden Sie es :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X