Detailed usage of IDisposable pattern in C

  • 2020-10-07 18:51:39
  • OfStack

This article illustrates the use of the IDisposable pattern in C# and explains the garbage collection in detail. To share with you for your reference. The specific methods are as follows:

First of all, for garbage collection, in C#, managed resource garbage collection is achieved through Garbage Collection of CLR, Garbage Collection will call the destructor of the object on the stack to complete the release of the object; For 1 unmanaged resources, such as database link objects, the IDisposable interface needs to be implemented for manual garbage collection. So when and how do you use the Idisposable interface?

First, let's refer to the following code:


public interface IDisposable
{
  void Dispose();
}
public class DisposablClass : IDisposable
{
  // Whether the recovery has been completed 
  bool _disposed;
  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
  ~DisposableClass()
  {
    Dispose(false);
  }
  
  // The parameters here indicate whether those implementations need to be released IDisposable The managed object of the interface 
  protected virtual void Dispose(bool disposing)
  {
    if(_disposed) return; // If it has been collected, the execution is interrupted 
    if(disposing)
    {
      //TODO: Release those implementations IDisposable The managed object of the interface 
    }
    //TODO: Frees an unmanaged resource and sets the object to null
    _disposed = true;
  }
}

Dispose () method

The Dispoase() method is called when the DisposableClass class needs to reclaim an unmanaged resource. This method will not be called automatically by CLR and will need to be called manually.

~DisposableClass(), destructor

When an object on the managed heap is not referenced by another object, GC calls the object's destructor before retrieving the object. The point of the ~DisposableClass() destructor here is to tell GC that you can recycle me, and Dispose(false) means that when GC recyles, there is no need to recycle manually.

Virtual method Dispose(bool disposing)

With this method, all managed and unmanaged resources can be recycled. The disposing parameter indicates whether managed objects that implement the IDisposable interface need to be released.

If disposings is set to true, it means that the DisposablClass class relies on some managed objects that implement the IDisposable interface and can be reclaimed by calling the Dispose() method of these managed objects through the Dispose(bool disposing) method here.

If disposings is set to false, which means that the DisposableClass class relies on some unmanaged resources that do not implement IDisposable, set the unmanaged resource objects to null and wait for GC to call the destructor of the DisposableClass class to reclaim the unmanaged resources.

In addition, the reason I set the Dispose(bool disposing) method to protected virtual above is that I want subclasses to be able to participate in the design of the garbage collection logic once and for all without affecting the base class. Let's say I have a subclass that looks like this:


public class SubDisposableClass : DiposableClass
{
  private bool _disposed; // Indicates whether it has been recycled 
  protected override void Dispose(bool disposing)
  {
    if(!_disposed) // If it hasn't been recycled 
    {
      if(disposiing) // If you need to recycle 1 Some managed resources 
      {
        //TODO: Reclaim managed resources, call IDisposable the Dispose() Method will do 
      }
      //TODO : Recycles an unmanaged resource and sets it to null And wait for CLR It is recovered when the destructor is called 
      _disposed = true;
    }
    base.Dispose(disposing);// The superclass garbage collection logic is then invoked 
  }
}

Before.NET 2.0, if an object's destructor threw an exception, the exception was ignored by CLR. However, after.NET 2.0, if the destructor throws an exception it will cause the application to crash. Therefore, it is important to ensure that the destructor does not throw exceptions.

Also, does the Dispose() method allow exceptions to be thrown? The answer is no. If there is a possibility that the Dispose() method will throw an exception, then you need to use try/catch to catch it manually. Here are some possible ways to consider exceptions to Dispose() :


public class DisposableClass : IDisposable
{
  bool _disposed;
  ......
  protected virtual void Dispose(bool disposing)
  {
    if(_disposed) return;
    if(disposing)
    {
      //TODO: Invoking a managed resource Dispose() Method for garbage collection 
    }
    try
    {
      _channelFactory.Close(); // There may be an exception when it is closed 
    }
    catch(Exception ex)
    {
      _log.Warn(ex);// log 
      try
      {
        _channelFactory.Abort();// There may be an exception when it is discarded 
      }
      catch(Exception cex)
      {
        _log.Warn(cex);// log 
      }
    }
    _channelFactory = null;
    _disposed = true;
  }
}

Summary: When we refer to some managed and unmanaged resources in our custom classes and their business logic, we need to implement the IDisposable interface to garbage collect these resource objects.

I hope this article has been helpful in achieving efficient C# programming.


Related articles: