You should be using using in CSharp

TLDR;

  • Use using instead of calling Dispose() manually whenever you can to keep instances from escaping their dispose call.
  • Refactor to reduce the need for curly braces and indentation.
  • Don't keep Database Connections around longer than needed

For extra points:

  • Implement IDisposable yourself when you see try and finally being repeated in a pattern.
  • ...but don't use the old Dispose pattern

Why use using?

A using statement in the C# looks like this:

using (Resource resource = expression)
...

It is used for disposing Resources, which implement the IDisposable interface as soon as they leave the scope and without manually calling it's Dispose() method.

The reason why this is useful is because there a ways that a disposable resource can escape the call of it's Dispose() method.

Let's start with an example and assume that the code in question calls Dispose() manually and starts simple:

var resource = new Resource();
resource.Dispose();

Now, that code is simple to read because it doesn't do to much - the Resource is created and immediately disposed again.

A more reasonable snippet of code would look like:

var resource = new Resource();
// Insert a block of arbitrary statements.
resource.Dispose();

What could possible go wrong in this ominous block of arbitrary statements?

1. Protection against exceptions

Probably the most common way that resources escape their Dispose() call are exceptions.

Let's take another look at the manual Dispose() call:

var resource = new Resource();
// Insert a block of arbitrary statements.
resource.Dispose();

If anything inside of the arbitrary statements block throws an Exception the execution stops before the resource.Dispose() call can be made.

If nothing at all catches the exception, then it's sometimes no problem, because usually the process is terminated anyway and the OS cleans up after the process by freeing it's resources like memory, files and sockets.

It's usually if some catch statement earlier in the call stack handles the Exception and tries to keep on running like nothing happened that the real problems start to emerge.

Luckily the using statement protects against exceptions by wrapping the statement following it into a try block and the Dispose() method in it's corresponding finally block.

So basically the following code:

using (var resource = new Resource())
{
  // Insert a block of arbitrary statements.
}

Is converted to something like the following:

{
  var resource = new Resource();
  try
  {
    // Insert a block of arbitrary statements.
  }
  finally
  {
    IDisposable d = (IDisposable)resource;
    if (d != null)
    {
      d.Dispose();
    }
  }
}

Thereby preventing the escape via thrown Exceptions.

I am pretty sure you already knew that, but wait, there's more!

2. Protects against Reassignment

Another way for an instance to escape could be a wrong reassignment. Let's assume that resource actually has some resource of finite length, for example a Buffer. An unknowing developer could swoop in and reassign a new value to the variable like so:

var resource = new Resource();
// A block of arbitrary statements
if (resource.Length < requiredLength)
{
  resource = new Resource(requiredLength);
}
// A block of arbitrary statements
resource.Dispose();

Now we have a bug - even though the resource.Dispose() call disposed an instance of the resource, it disposes only the second instance that was assigned inside the if statement - the first instance escapes.

By using the using statement (hehe) that potential error can't happen, because the code:

using (var resource = new Resource())
{
  // A block of arbitrary statements
  if (resource.Length < requiredLength)
  {
    resource = new Resource(requiredLength);
  }
  // A block of arbitrary statements
}

Results in the following compile-time error:

Cannot assign to 'resource' because it is a 'using variable' (CS1656)

There is one more advantage, that's kind of an extension of the reassignment protection.

3. Protects against ref shenanigans and out misuse

Additionally, the using statement prevents passing the parameter by ref, which would allow a reassignment of the variable from another method.

So the following code:

using (var resource = new Resource())
{
  // A block of arbitrary statements
  DoSomething(ref resource);
  // A block of arbitrary statements
}
...
void DoSomething(ref Resource resource)
{
  resource = new Resource();
}

...also doesn't work and the following compile-time error is triggered:

Cannot use 'resource' as a ref or out value because it is a 'using variable'

As the error message hints, the same compile-time error is also shown if the variable is passed as an out parameter.

Which is fine by me, because it doesn't make much sense for a method to produce already disposed objects, which commonly throw ObjectDisposedExceptions when any member is accessed after they got disposed.

With advantages like that, you would assume that everybody is using the using statement whenever they can, wouldn't you?

I found out that's not always the case. The reasons for that are often myths about using and IDisposable that pop up as objections from time to time. That's why I decided to tackle them here as well.

Myths that developers believe about using

So without further ado I present to you the top 4 myths why developers don't use using / IDisposable:

  1. Multiple using statements introduce too many indentations / curly braces / nested code blocks!
  2. I can't dispose the Database Connection, I will need it later again!
  3. I've got nothing to dispose!
  4. I need to implement the dispose pattern!

Let's look at each objection separately and see what we can do.

1. Too much Indentation

From time to time I hear developers complaining about the additional levels of indentation and curly braces that can be introduced by using a lot of using statements.

Let's take a look at a simple example that accesses our 3rd most popular Database and loads an entry with the matching id from a table.

namespace UsingExample
{
    public class CustomerRepository : ICustomerRepository
    {
        string GetConnectionString()
            => "...";

        public CustomerModel GetCustomerById(int id)
        {
            CustomerModel customer;

            using (var tran = new TransactionScope())
            {
                using (var conn = new SqlConnection(GetConnectionString()))
                {
                    conn.Open();
                    using (var cmd = new SqlCommand("select * from Customer where Id = @Id", conn))
                    {
                        cmd.Parameters.AddWithValue("Id", id);
                        using (var dr = cmd.ExecuteReader())
                        {
                            if (dr.Read())
                            {
                                customer = new CustomerModel
                                {
                                    Id        = (int)   dr["Id"],
                                    Firstname = (string)dr["Firstname"],
                                    Lastname  = (string)dr["Lastname"],
                                };
                            }
                            else
                                customer = null;
                        }
                    }
                }
            }

            return customer;
        }
    }
}

Note: The TransactionScope is not really needed here, it only enforces that the command is really unable to modify anything, as it is automatically rolled back when it leaves the scope.

Now you can argue that those indentation levels are problematic - and honestly - I would agree, because IMHO even though the code is not doing a lot, it is already pretty hard to read.

But that's not an issue with using using! Heck, you've got the same problems if you nest your ifs deeply. So the solution is not using fewer usings, but refactoring your code!

The similarity to if doesn't end here, because using statements can skip the curly brackets, just like with an if statement. When you skip the curly braces {} after an if statement, you'll want to indent the next statement, so that it's clear that it is being affected by the if. But the thing is, you are not required to.

While we don't want to take advantage of that freedom with an if statement, we maybe want to do that in the case of the using statement.

So instead of:

using (var tran = new TransactionScope())
{
    using (var conn = new SqlConnection(GetConnectionString()))
    {
      ...
    }
}

we can just write:

using (var tran = new TransactionScope())
using (var conn = new SqlConnection(GetConnectionString()))

Okay, but that trick alone does not get rid of all identations! Let's take a look at how we use the SqlConnection:

using (var conn = new SqlConnection(GetConnectionString()))
{
    conn.Open();
    using (var cmd = new SqlCommand("select * from Customer where Id = @Id", conn))
    {
      ...
    }
    ...
}

If it weren't this pesky conn.Open() call! It keeps us from just skipping the curly braces on the using statement with the new SqlConnection().

The reason is, that if you skip the curly braces {} the using variable will only be available for the following statement - in this case the conn.Open() call, but not for any statements after it, like the line were we actually use it in the SqlCommand constructor.

So what do we do in that case? The same thing that we do with too deeply nested if statements: we refactor them!

In this case, I am going to create a method for setting up the SqlConnection, including the conn.Open() call:

SqlConnection GetOpenConnection()
{
    var conn = new SqlConnection(this.GetConnectionString());
    conn.Open();
    return conn;
}

...and because I am on a roll, I am going to do the same thing for the SqlCommand and it's Parameters.AddWithValue() call:

SqlCommand GetSelectCustomerByIdCmd(int id, SqlConnection conn)
{
    var cmd = new SqlCommand("select * from Customer where Id = @Id", conn);
    cmd.Parameters.AddWithValue("Id", id);
    return cmd;
}

While we are at it, we can also refactor the reading of the CustomerModel into it's own method:

CustomerModel ReadCustomer(IDataReader dr)
{
    CustomerModel customer;

    if (dr.Read())
    {
        customer = new CustomerModel
        {
            Id        = (int)   dr["Id"],
            Firstname = (string)dr["Firstname"],
            Lastname  = (string)dr["Lastname"],
        };
    }
    else
        customer = null;

    return customer;
}

Now we can use them in the final refactored GetCustomerById() method:

public CustomerModel GetCustomerById(int id)
{
    using (var tran = new TransactionScope())
    using (var conn = GetOpenConnection())
    using (var cmd = GetSelectCustomerByIdCmd(id, conn))
    using (var dr = cmd.ExecuteReader())
        return ReadCustomer(dr);
}

I would argue that this is much better than what we had in the beginning:

  • We've got rid of the identation and the curlies and even if we want to keep the indentation, it's now really easy to read.
  • We've got smaller methods that do less each and they only have one single concern instead of a big method that does all the things.
  • ...but wait, there's even more! Now the code is also easy to extend!

As an example imagine that we now want to retrieve Customers in a slightly different way, for example retrieve all Customers at once. The only thing we need to do is implement two teeny-weeny methods that follow the same pattern as before:

SqlCommand GetSelectAllCustomersCmd(SqlConnection conn)
    => new SqlCommand("select * from Customer", conn);

public CustomerModel[] GetAllCustomers()
{
    var customers = new List<CustomerModel>();
    CustomerModel customer;
    using (var tran = new TransactionScope())
    using (var conn = GetOpenConnection())
    using (var cmd = GetSelectAllCustomersCmd(conn))
    using (var dr = cmd.ExecuteReader())
        while ((customer = ReadCustomer(dr)) != null)
            customers.Add(customer);
    return customers.ToArray();
}

...and we are done!

2. I can't dispose the Database Connection, I will need it later again

This one is not about the IDisposable interface, but about specific implementations - Database Connection - e.g. SqlConnection.

So on one hand opening a Database Connections is an expensive operation.

On the other hand, you should always hold onto disposable resources for the least amount of time possible.

Okay, but who wins in that case? Luckily we don't have to decide, because ADO.NET implements ConnectionPooling.

This means that a so-called pooler inside of the Framework holds onto the physical connection, even after we've called it's Dispose() method.

As a result opening the Connection the first time is just as slow as always, but the second and all consecutive times when we open the connection we don't pay that performance overhead - as long as the underlying physical connection is available and can be reused, of course.

This gives us the benefits of both worlds - a simple resource management strategy where we can just ask for a new Connection when we need it and dispose it immediately afterwards, but also great performance, because the underlying physical connection is being kept alive and reused, if possible.

So for Database Connections that means you should dispose them as soon as you are done with your operation, as you can see in the methods GetAllCustomers() and GetCustomerById() above.

3. I've got nothing to dispose

Okay, that's a valid reason - how could you possibly call Dispose() if you don't have a class that implements the IDisposable interface?

Well, sometimes it makes sense to implement IDisposable even if you don't have unmanaged resources to free.

So what I've found is that the using statement is also useful to wrap logic that you normally would want to encapsulate in a try/finally block - with the additional advantages of reassignment protection as explained above.

For just a one-time use, this doesn't make sense of course, but if you happen to see this as a pattern repeating in your code than wrapping the try/finally in an IDisposable makes sense.

As an example, image you want to control the number of concurrent requests to a contested resource in a multithreaded application e.g. like your webserver.

You've setup your contested resource and an instance of SemaphoreSlim to the maximum number of concurrent requests that you are comfortable with, like so:

this.contestedResource = new ContestedResource();
this.semaphoreSlim = new SemaphoreSlim(initialCount: 1, maxCount: 1);

And you now implement the async wrapper that wraps the calls to the contested Resource (without blocking the calling thread, thanks to SemaphoreSlims WaitAsync() method).

To not mess up the system with deadlocks if an exception is thrown when calling the contested resource, you make sure to wrap the call in a try block and release the semaphore in the finally block, like so:

public async Task<Result> GetFoo(CancellationToken ct)
{
  await this.semaphoreSlim.WaitAsync(ct);
  try { return this.contestedResource.GetFoo(); }
  finally { this.semaphoreSlim.Release(); }
}

public async Task<Result> GetBar(CancellationToken ct)
{
  await this.semaphoreSlim.WaitAsync(ct);
  try { return this.contestedResource.GetBar(); }
  finally { this.semaphoreSlim.Release(); }
}

public async Task<Result> GetBaz(CancellationToken ct)
{
  await this.semaphoreSlim.WaitAsync(ct);
  try { return this.contestedResource.GetBaz(); }
  finally { this.semaphoreSlim.Release(); }
}

...

When you look at that code, you can see that a specific pattern repeats itself:

  1. It starts with the resource acquisition, which is always the same call: await this.semaphoreSlim.WaitAsync(ct)
  2. Then custom code inside a try block is executed
  3. Then the resource is released inside a finally statement: finally { this.semaphoreSlim.Release(); }

Isn't that exactly what using provides? So let's create code that wraps the semaphore usage in an IDisposable interface so that we can apply using:

The implementation will be split in two parts, the first one being the class that keeps track of the SemaphoreSlim instance and is able to hand out disposable tokens. The second class is the disposable token.

First I'll start with the class that generates the tokens, I've called it AsyncLock:

public sealed class AsyncLock : IDisposable
{
    private readonly SemaphoreSlim semaphoreSlim;

    public AsyncLock()
        => this.semaphoreSlim = new SemaphoreSlim(1, 1);

    public async Task<IDisposable> WaitAsync()
        => await LockToken.WaitAsync(this.semaphoreSlim);

    public void Dispose()
        => this.semaphoreSlim.Dispose();
}

AsyncLock is able to do 3 things:

  1. Initialize the SemaphoreSlim in the constructor.
  2. Return an IDisposable instance by creating a new LockToken instance.
  3. Propagate the Dispose to it's SemaphoreSlim instance.

Next comes the class that is returned from a call to AsyncLock.WaitAsync(), which I've called LockToken:

sealed class LockToken : IDisposable
{
    private readonly SemaphoreSlim semaphoreSlim;
    private bool isDisposed = false;

    private LockToken(SemaphoreSlim semaphoreSlim)
      => this.semaphoreSlim = semaphoreSlim;

    public static async Task<LockToken> WaitAsync(SemaphoreSlim semaphoreSlim)
    {
        await semaphoreSlim.WaitAsync();
        return new LockToken(semaphoreSlim);
    }

    public void Dispose()
    {
        if (!this.isDisposed)
        {
            this.semaphoreSlim.Release();
            this.isDisposed = true;
        }
    }
}

This class is basically a fancy wrapper for calling this.semaphoreSlim.Release() that is called with using.

Note: The LockToken class guards against calling this.semaphoreSlim.Release() multiple times, by keeping track if it was already disposed.

Now we can rewrite our wrapper like that:

public async Task<Result> GetFoo(CancellationToken ct)
{
  using (var _ = await this.asyncLock.WaitAsync())
      return this.contestedResource.GetFoo();
}

public async Task<Result> GetBar(CancellationToken ct)
{
  using (var _ = await this.asyncLock.WaitAsync())
      return this.contestedResource.GetBar();
}

public async Task<Result> GetBaz(CancellationToken ct)
{
  using (var _ = await this.asyncLock.WaitAsync())
      return this.contestedResource.GetBaz();
}

And in addition we get this nice utility class that we can use for async locking.

4. I need to implement the dispose pattern

First of all, what is the dispose pattern? Basically, it's a pattern of how to implement the IDispose interface.

But instead of just implementing the single method of this interface, namely void Dispose(), it also consists of an additional overload, usually protected virtual void Dispose(bool disposing) and a finalizer implementation, which in C# is Done via the ~Classname().

Now, in the past, this pattern was the recommended directly by Microsoft, but they changed that recently and now the recommendation is, that you wrap unmanaged resources in an SafeHandle instance and don't implement the finalizer at all.

They still recommend to keep the protected virtual Dispose(bool disposing) overload so that derived classes can also get rid of their resources.

Okay, so we got rid of the Finalizer and if we don't have unmanaged resources to track we need zero SafeHandles!

What about the protected virtual Dispose(bool disposing) overload? Luckily there is a very simple solution to that: stick sealed on the class to deny any inheritance and you're done!

So in a situation, were you have only Managed Resources that implement IDisposable themselves your implementation can be done in two steps:

  1. Implement IDisposable and dispose managed resources in your Dispose() method.
  2. Make the class sealed.

The lengthy and slightly confusing documentation for implementing IDispose can be found here and if you made it through this document, be sure to check out the discussions in the associated issues, like this one.

Summary

The using statement in C# prevents an instance escaping it's Dispose() call by protecting against exceptions and reassignment (either directly or by forwarding by ref).

Objections against using/IDisposable are common but most are easily solved:

Indentation and deeply nested code blocks can be solved via refactoring, Database Connection can be freely disposed, because Connection Pooling speeds up their recreation and the recommended dispose pattern has changed and can be shortcutted in most cases.

Additionally, using/IDisposable gives access to a nice abstraction over try/finally that we can use ourselves whenever we see that pattern repeating.

So please keep on using using!

References