Bulletproof Disposable Types In .NET Core

Whenever I do code review on .NET projects, hands down the number one issue is developers not calling .Dispose() on disposable objects. Ever since .NET was released, I have been preaching how important this is. If not done properly, it’s most likely to create virtual memory issues that will eventually cause the application to stop and possibly freeze server or users’ computer.

Recently, after doing code review on a company code base, I had a meeting with the development manager. I asked him “Do you have any back-end servers that you need to re-boot on a regular basis?”. He said “YES”! I told him “I know exactly what the issues is!”. The issue is most of their code, if not all of it, did not call .Dispose() on any disposable object. It took me about three months just to fix them all!

How do you know if all of your code is calling Dispose properly?

Well, since FXCop or Analyze do NOT support .NET Core, the only way at the time of writing of this article is to run the static code analyzer called CodeIt.Right from Submain.com. The cool thing is that with CodeIt.Right, all you need to do to fix it is to press the “Correct” button on the violation and CodeIt.Right will fix it for your using the proper pattern.

Making Dispose Easier

A while ago, I wrote extension methods to make calling .Dispose() easier in my open source assemblies, now on NuGet.org. Just install the dotNetTips.Utility.Standard.Extensions package. Not using .NET Core, as long as your project uses .NET 4.6.1, this package can still be used.

Disposing Local Variables

To dispose of a variable, I created the .TryDispose() extension method. Here is an example on how to use it:

disposableObject.TryDispose();

TryDispose() checks to make sure the object isn’t null and then calls .Dispose(). If the code uses a “using” block, then it calls .Dispose() for you and it wouldn’t need to use this method.

Disposing Fields

That is great for a variable but how about a type that has disposable fields? I created a method for that too called .DisposeFields(). Here it is in action using the proper IDisposable pattern:

  1. protected bool disposed;  
  2. public virtual void Dispose() {  
  3.     Dispose(true);  
  4.     GC.SuppressFinalize(this);  
  5. }  
  6. protected virtual void Dispose(bool disposing) {  
  7.     if (this.disposed) {  
  8.         return;  
  9.     }  
  10.     if (disposing) {  
  11.         this.DisposeFields();  
  12.     }  
  13.     this.disposed = true;  
  14. }  

DisposeFields() looks at all the fields in the object and if any are, then .Dispose() is called. The cool thing about this method is that it prevents another developer from adding a new IDisposable field and not add it to the .Dispose() call. I call this “Future Proofing”.

Disposing Collections

I’ve been using these two extension methods for a long time. But recently, I found that a client of mine is putting disposable objects into a collection. I’ve never used a collection like that, so I wrote a method for that too called .DisposeCollection() that works with IEnumerable, IEnumerable<T> and IDictionary<TKey, TValue. DisposeFields() will check to see if the object supports IEnumerable, if it does, then it also calls .DisposeCollection().

Making Sure There Aren’t Any Virtual Memory Leaks

One downside to using code analyzers to find IDisposable issues is that I have yet to find one that finds everything. The way I know to find every last issue is to use a memory profiler. The ONLY way to find them all is to run the code preferably on a near to production setup.

The memory profiler I use is to call .NET Memory Profiler from SciTech Software AB. I’ve tried all the major profilers out there and this one works the best, even in .NET Core. It helps me easily drill down to where the possible memory leak is and even see the data it contains. Be warned … tracking down issues in a profiler can take a while due to all the false positives. There are more things that this memory profiler can find so I recommend checking it out before your project goes into production.

Don’t forget to install my dotNetTips.Utility.Standard NuGet package for this code and lots more. The source can be found on GitHub.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!