Archive for March, 2011

Automatically disposing IDisposable?

Reading up on Ruby, I was intrigued by the way file operations are handled. Primarily the fact that Ruby allows you to pass a block as a parameter to Open method of a File object. When you do this it opens the file for you, passes the file to the block, and then closes the file when the block is done executing, relieving you of having to manage checking to make sure the file is open, as well as making sure that the file is closed when your are done using it.

Below is the example that is shown in Programming Ruby by Dave Thomas.

File.open("archive.log", "a") do |f|
  f.each_line { |line| puts "Got #{line.dump}" }
end

This ability seemed similar to how the FileStream returned from File.Open in C# implements IDisposable, and by putting that FileStream object in a using block, the .NET Framework will call disposable when that block is exited. But what struck me, was that every time you get a FileStream object, it needs to be put in a using block. I have stubbed out an example of this against a call to the method ExecuteReader on the SQLCommand class.

public class Test
{
	public void RunQuery()
	{
		string queryString = "testQueryString";
		SqlConnection connection = new SqlConnection("myConnectionString");
		SqlCommand command = new SqlCommand(queryString, connection);
		DbDataReader reader = command.ExecuteReader();
		using (SqlDataReader reader = command.ExecuteReader())
		{
			while (reader.Read())
			{
				Console.WriteLine(String.Format("{0}", reader[0]));
			}
		}
	}
}

While I do strongly agree the using block greatly improved the way we would have had to deal with closing the reader previously in .NET, after seeing the way Ruby deals with this. The reason I think Ruby handles this better is that for a number of scenarios the responsibility of disposing the object should be hidden from the consumer if possible. So I suggest that in the future, when designing your method calls the goal should be to make the disposing of the IDisposable automatic, at least from the point of view from the consumer. This helps reduce boiler plate code that has to be duplicated every where the method is used. The other reason that this is helpful, is that it prevents the consumer from forgetting to dispose of the object when they are done with it. It may also be helpful to create extension methods for those API calls you have no control over to give you this functionality as well, as shown below.

public static class FileExtensions
{
	public static void ExecuteReader(this SqlCommand command, Action block)
	{
		using (SqlDataReader reader = command.ExecuteReader())
		{
			block(reader);
		}
	}
}

public class Test
{
	public void RunQuery()
	{
		string queryString = "testQueryString";
		SqlConnection connection = new SqlConnection("myConnectionString");
		SqlCommand command = new SqlCommand(queryString, connection);
		command.ExecuteReader(reader =>
		{
			while (reader.Read())
			{
				Console.WriteLine(String.Format("{0}", reader[0]));
			}
		});
	}
}

Based on this we can even enhance this functionality and encapsulate the DbDataReader completely and pass a different type of object to the block if we decide that we have a better abstraction to work against.

Note: I almost decided not to post this, as I was at the Dallas Day of Dot Net this weekend and pinged Derick Bailey about this for his perspective as a developer who used both Ruby and .Net, and he mentioned his blog post How Ruby Taught Me To DRY Up My Code With Lambda Blocks on the topic.  So go read his entry as well, and try this out for yourself and let me know how this works for you.

Advertisements

2 Comments