简体   繁体   中英

C# BlockingCollection Dispose method

Documentation of BlockingCollection<T> class has the following note:

Always call Dispose before you release your last reference to the 
BlockingCollection<T>. Otherwise, the resources it is using will not be freed 
until the garbage collector calls the BlockingCollection<T> object's Finalize 
method.

And internal implementation of BlockingCollection<T> in C# has the following method:

/// <summary>
/// Releases resources used by the <see cref="T:System.Collections.Concurrent.BlockingCollection{T}"/> instance.
/// </summary>
/// <param name="disposing">Whether being disposed explicitly (true) or due to a finalizer (false).</param>
protected virtual void Dispose(bool disposing)

There is only one call of this Dispose with argument disposing: true and finalization suppress after the call. But, surprisingly for me, there is no explicit finalizer in the class, and even no call of Dispose(false) . It looks like Dispose function is relatively simple and it just removes references to different objects for GC speed up. In this case, GC will do this work for us in the case when we forget to call Dispose() explicitly.

Can someone spot the light on the internals of this class? What is the purpose of a method Dispose(bool disposing) ? Is it common practice to implement this method for .NET core libraries even in cases when it is not needed?

I think the MSDN documentation for how to properly implement the dispose pattern is worth a read. However, the answer to your question is that BlockingCollection is not sealed. This means that it can be derived. The reason for the void Dispose(bool disposing) is to allow derived classes to properly de-allocate the resources of the base class. So, for example, I could implement

class Foo : BlockingCollection<string>
{
  private bool disposed = false;

  ~Foo()
  {
    Dispose(false);
  }

  protected override void Dispose(bool disposing)
  {
    if (disposed)
    {
      return;
    }

    if (disposing)
    {
      // free managed resources
    }

    // free unmanaged resources

    disposed = true;
    base.Dispose(disposing);
  }
}

By doing this, when Dispose() is called, the BlockingCollection will call Dispose(true) on Foo, which will eventually call Dispose(true) on BlockingCollection, and you get the benefit that the ~Foo() finalizer is suppressed. If the Dispose() method is not called, the finalizer is not suppressed, and it is called, allowing Foo to still deallocate its unmanaged resources.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM