FANDOM


OverviewEdit

C# objects that own resources that are disposed follow the IDisposable pattern.

As a byproduct of having a garbage collector, C# class destructors are not called deterministically. That is, one can’t determine exactly when the object’s destructor is going to be called, if at all. Techniques common in C++ that release resources in the destructor of a class when the object goes out of scope is not a good model for C#. This document will describe how this problem is typically solved and some recommendations.

BackgroundEdit

What is the problem and why do I have to do deal with this!Edit

When working in a managed environment, it’s dangerous to simply put your clean-up code in the destructor as you’re used to doing in C++ because you never know when that destructor is going to be called. Garbage collection only manages one type of resource – memory, and that’s the only resource that can impact how the garbage collection works; for instance, if you have enough available RAM, the garbage collection may not run for a while. However, if you have unmanaged resources attached to these objects that you expect to get cleaned up, you may run out of those resources -- the garbage collector isn’t aware of them and won’t “kick-in” to clean them up. For instance, say you can only have 64 available sockets – if you rely on the destructor to release your socket connection, and the computer has lots of RAM, the objects associated with those sockets may be alive for a long time, the sockets won’t close, and the program will fail when it attempts to create a new socket connection and none are available. So another system is devised – one that requires the client of your object to explicitly call a method of your class that will clean-up your resources.

Even if you decide to use your own scheme for dealing with resource relinquishment, you will likely have to read code that follows common patterns published by Microsoft. Namely, any component derived from IComponent, including Windows Forms controls, will use a pattern for disposing acquired resources. The rest of this document provides several solutions to the problem, each one building upon the previous, and concluding with the richest (albeit more complex) solution. Each solution is summarized with a set of Pros and Cons so that the reader may assess whether that solution will fit their specific needs.

[It’s important to realize that the CLR garbage collector takes care of all managed resources (“managed”, by definition, means any object under the control of the CLR garbage collector.) The patterns described in this page are only needed when dealing with external resources, such as files, connections, windows, etc. This pattern may not be used by all classes as it incurs a performance penalty. Only classes that managed unmanaged resources are to use the Dispose pattern.]

Garbage Collector works differently between .Net Release and Debug builds such as at which point an object is garbage collected.

Level 1 – Roll your ownEdit

I can just roll my own – at least I know what it does – so let’s start with that.

Let’s assume that you are going to create a class in C# which connects to some service in the class’ constructor. When the user of the object is done, they’re supposed to invoke a method on the object which disconnects the service. The service here can be anything, such as opening a connection to a remote node (which needs to be disconnected when done) or a disk file being opened (which needs to be closed when done.) Here’s a simple class that would do that:

public class Server
{
	public Server()
	{
		// … connect to the service here.
	}

	public void Dispose() 
	{
		// … disconnect from the service here.
	}
}

Here, there’s nothing special about this Dispose() method – the CLR doesn’t know anything about it. The client that uses the Server class will need to call the Dispose() method when they’re done using the object.

Here’s an example client using this class. To insure that Dispose() always gets called even if an exception is thrown, the client code uses a try / finally block:

Server srv;
try
{
	srv = new Server();

	// use the server here
}
finally
{
	srv.Dispose();
}

Other classes can have data members of type Server, in which case those classes supply their own Dispose methods which call Server’s Dispose. Example:

public class Controller
{
	private Server srv = new Server();

	// … other methods

	public void Dispose() 
	{
		srv.Dispose();
	}
}

Inheritance is supported. A class may be derived from Server. The derived classes delegates calls to their Dispose() method down to the base classes. In this case the Dispose method in the base class above needs to be virtual. Here’s an example derived class:

public class ServerEx : Server
{
	// … other methods

	public void override Dispose() 
	{
		base.Dispose();
	}
}

SummaryEdit

Pros:Edit

  1. It works and it’s simple to explain.
  2. Inheritance is supported.

Cons:Edit

  1. The client remembers to call Dispose, or else resources will leak.
  2. try / finally block is a bit cumbersome to use.
  3. Client is aware that there’s a Dispose method that needs to get called. This will likely be supplied with the API documentation.

Level 2 – Implement IDisposable and use C#’s using statementEdit

The technique in the previous sample assumes that the client is aware that they ought to call the Dispose method on the object when they’re done using it. Typically this is communicated via class documentation.

Naming the disposing method “Dispose” became a convention within the .NET Framework so much so that Microsoft decided to standardize on the name and place the method in an interface called IDisposable. To use this pattern, you can implement IDisposable and supply a Dispose(). Example:

public class Server : IDisposable
{
	public Server()
	{
		// … connect to the service here.
	}

	public void override Dispose() 
	{
		// … disconnect from the service here.
	}
}

There are several advantages to this. One is that anyone looking at the definition of your class will know that you’re using the dispose pattern simply because your class is implementing IDisposable. Another advantage is that a client could query for IDisposable on an object at runtime to determine if it uses the dispose pattern and then call the Dispose method if it’s implemented. New to C# is the using statement which uses the latter technique such that if your class implements IDisposable, the using statement will call the Dispose() method automatically – this produces cleaner looking client code. The code above which uses the try / finally block can be rewritten using the using statement. The resulting object code of both would be identical. Example:

BEFORE:

Server srv;
try
{
	srv = new Server();

	// use the server here
}
finally
{
	srv.Dispose();
}

AFTER:

using( Server srv = new Server() )
{
	// use the server here
}

SummaryEdit

Pros:Edit

  1. Implementing IDisposable documents that the dispose pattern is used.
  2. The using syntax is nicer than try / finally blocks

Cons:Edit

  1. The client remembers to use the using clause, or else you’re resource will leak.

Level 3 – Make “leaks” more obvious when they occur.Edit

What happens when the client forgets to call Dispose? Clearly they made a mistake. But rather than be silent, we can let them know by using a simple convention: have the Dispose method suppress finalization and then log an error in the destructor. This way, if a client forgets to call dispose, the destructor won’t be suppressed, so when the Garbage Collector finally calls it, it will log an error. Example:

public class Server : IDisposable
{
	public Server()
	{
		// … connect to the service here.
	}

	~Server()
	{
		Logger.LogError( this.GetType().FullName + " instance not properly disposed" );
	}

	public void virtual Dispose() 
	{
		// … disconnect from the service here.

		// Suppress calling the destructor.
		GC.SuppressFinalize( this );
	}
}

We could stop now. We have a decent solution which addresses most scenarios. Here’s a template you can use if you wish to use pattern described up to now:

// Simplified pattern.  Caveat: We assume clients will call Dispose()
// as necessary.
public class MyClass : IDisposable
{
	// IDisposable 
	public virtual void Dispose() 
	{
		// Free managed and unmanaged objects.
		// ...

		// Suppress calling the destructor.
		GC.SuppressFinalize( this );
	}

	~MyClass()
	{
		Logger.LogError( this.GetType().FullName +
" instance not properly disposed." );
	}
}

SummaryEdit

Pros:Edit

  1. If a client forgets to call Dispose, they’ll see an error in the logger.

Cons:Edit

  1. If a client forgets to call Dispose, they’ll still leak.

Level 4 – Handling bad clientsEdit

Microsoft has gone further and refined the above pattern to support environments where clients fail to call Dispose. The more complex pattern presented here is used by the stock implementations of framework classes which implement IComponent, including Windows Forms Controls, so it’s good to understand it even if you don’t use it in your classes. This pattern is especially usefully if you’re going to expose your class to clients whose code you don’t control.

The Dispose Pattern used by MicrosoftEdit

To recap, thus far we have a class which implements IDisposable, places its resource freeing code in the Dispose() method and sets up to suppress finalization so that the destructor does not get called needlessly (and logs an error if it does.) The pattern is now being extended to support those clients which do not properly call the Dispose method. The simple idea is to have the destructor call Dispose() but only when the client forgets to do it. The idea is that if the client doesn’t call Dispose, the object will call Dispose on itself when it is eventually finalized. A simplistic solution may look like this:

public class Server : IDisposable
{
	public Server()
	{
		// … connect to the service here.
	}

	~Server()
	{
		Dispose();
	}

	public void virtual Dispose() 
	{
		// … disconnect from the service here.

		// Suppress calling the destructor.
		GC.SuppressFinalize( this );
	}
}

The above has a problem that needs to be overcome:

  • If the code that frees resources in the Dispose() method accesses other objects, it may crash if those other objects have already been finalized. This means that the code in the Dispose() method only frees unmanaged resources when it’s called during finalization. But, the same Dispose method frees both managed and unmanaged resources if it’s called by the client. The solution is to factor out the disposing code into another method -- an overload of Dispose that takes a boolean parameter indicating whether the code is being called by a client or from the destructor.

Here’s the complete solution:

public class Server : IDisposable
{
	public Server()
	{
		// … connect to the service here.
	}

	~Server()
	{
		Dispose( false );
	}

	protected void virtual Dispose ( bool disposing )
	{
		if ( disposing )
		{		
			// Free other state (managed objects).
		}

		// Free your own state (unmanaged objects).
	}

	public void Dispose() 
	{
		Dispose( true );
		GC.SuppressFinalize( this );
	}
}

The parameterless overload of Dispose implements the IDisposable interface. The one with the bool parameter is internal and is called only by the destructor, the public Dispose and possibly by any derived classes (which is why it’s protected.) [Don’t ask me why the same name is used for both methods.]

Although not strictly part of the Microsoft pattern, it’s useful to still indicate in the logger when a client fails to call the Dispose method, even when the object eventually disposes itself when it’s finalized. The template for the final solution includes this change – use this template: Complex template (http://devpedia/wiki/.NET_Disposable_Objects#Class_template)

Even more complexEdit

You may see further refinements of the above in several MSDN articles. One is to store in a data member whether the object is in the middle of being disposed. That flag is then used to check, at the top of every method of that class, that no client is calling the method while the object being disposed. We believe that such scenarios can be avoided altogether by proper design – if a client were to call those methods after the object already got disposed, it wouldn’t work anyway, and there would be no way for that object, which has since been destroyed, to cope with that situation.

SummaryEdit

Pros:Edit

  1. If a client forgets to call Dispose, the unmanaged resources will likely get freed when the object is later finalized.

Cons:Edit

  1. Object finalization may never be called, or if it is called, is only called by the garbage collector when it needs more memory. When the system has enough memory, objects may not finalize for a long time. But the unmanaged resources allocated by those objects (socket connections for instance) will likely be a more scarce resource than RAM and will therefore run-out before those objects are finalized. So this solution only makes things a little bit better. Bad clients will still cause problems, just not as much. A “clean up … deferred” warning reported in the logger is an indication of a bug in the client and needs to be fixed, if client code is available.

TemplatesEdit

Class templateEdit

To use the pattern directly, copy-paste the following into your code and rename “MyClass”. (Alternatively, you can derive your class from the provided Disposable class below, but that only works if your class doesn’t already derive from another base class.)

// Microsoft pattern as used by Components and Controls.
public class MyClass : IDisposable // or IComponent if to be designable
{
	// IDisposable 
	public void Dispose() 
	{
		Dispose( true );
		GC.SuppressFinalize( this );
	}

	protected virtual void Dispose( bool disposing )
	{
		if ( disposing ) 
		{
			//Free other state (managed objects).
			// ...
		}
		//Free your own state (unmanaged objects).
		// ...
	}

	~MyClass()
	{
		// Bad client code
		Logger.LogWarning( "Clean up of unmanaged resource was deferred to garbage collector.  Client of '" + this.GetType().FullName + "' failed to call Dispose()." );
		Dispose( false );
	}
}

Or if provided base class, Disposable, is used then the above can be written as:

public class MyClass : Disposable
{
	protected override void Dispose( bool disposing )
	{
		if ( disposing ) 
		{
			//Free other state (managed objects).
			// ...
		}
		//Free your own state (unmanaged objects).
		// ...
	}
}

Disposable base class – may be placed in a ClassUtility:

public abstract class Disposable : IDisposable
{
	// IDisposable 
	public void Dispose() 
	{
		Dispose( true );
		GC.SuppressFinalize( this );
	}

	protected abstract void Dispose( bool disposing );

	~Disposable()
	{
		Logger.LogWarning( "Clean up of unmanaged resource was deferred to garbage collector.  Client of '" + this.GetType().FullName + "' failed to call Dispose()." );
		Dispose( false );
	}
}

Note that although deriving from Disposable is preferred, it will only work if your class does not already inherent from another class (based on multiple-inheritance limitation in C#/.NET)

This page is an example of Catching defects with Patterns.

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.