Skip to content
IDisposable and using
step 1/6

Reading — step 1 of 6

Learn

~2 min readModern C#

In .NET, the GC handles memory but NOT other resources — file handles, sockets, DB connections, locks. The IDisposable pattern is how you ensure these get cleaned up promptly.

The interface

public interface IDisposable
{
    void Dispose();
}

Any class holding non-memory resources should implement IDisposable. The convention: callers MUST call Dispose() when done.

using statement — automatic disposal

using (var stream = File.OpenRead("data.txt"))
{
    // use stream
}   // stream.Dispose() called here, even on exception

The using block ensures Dispose runs no matter what — like try/finally. This is the DEFAULT pattern for any IDisposable.

using declarations (C# 8+)

The newer form scopes to the enclosing block:

void ReadFile()
{
    using var stream = File.OpenRead("data.txt");
    // ... do work ...
}   // stream.Dispose() at end of method

No extra braces. Cleaner for single-resource cases.

Multiple resources

using var input  = File.OpenRead("in.txt");
using var output = File.Create("out.txt");
input.CopyTo(output);
// both disposed in reverse declaration order

Or nested:

using (var conn = new SqlConnection(connStr))
using (var cmd  = conn.CreateCommand())
{
    // ...
}

Implementing IDisposable correctly

For classes that own resources:

public class TempFile : IDisposable
{
    private readonly string path;
    private bool disposed;

    public TempFile()
    {
        path = Path.GetTempFileName();
    }

    public void Dispose()
    {
        if (disposed) return;
        try { File.Delete(path); } catch { /* log */ }
        disposed = true;
        GC.SuppressFinalize(this);
    }
}

The disposed flag ensures Dispose is idempotent. GC.SuppressFinalize tells the GC it doesn't need to call any finalizer (improves performance).

Grader note: using var is C# 8+ syntax — the exercise grader runs Mono's C# 7 compiler, so write the classic block form using (var r = new Resource()) { ... } in your solution.

IAsyncDisposable

For async cleanup (Stream.DisposeAsync, etc.):

await using var stream = File.OpenRead("data.txt");
// stream.DisposeAsync() called at end of scope

The await using runs the asynchronous Dispose. Useful for things that need to flush or commit asynchronously.

When to implement IDisposable

You need it when your class:

  • Owns a Stream, SqlConnection, HttpClient, etc. (anything IDisposable)
  • Holds OS handles (P/Invoke, file descriptors)
  • Subscribes to long-lived events (so Dispose can unsubscribe)
  • Acquires locks, semaphores, etc.

If your class only holds managed memory (strings, lists, etc.), you don't need IDisposable.

Common mistakes

  • Forgetting using — resources leak until GC runs Finalize, which may be never.
  • Disposing what you didn't create — only the owner should dispose. Borrowed instances stay open.
  • Calling Dispose then continuing to use — typically throws ObjectDisposedException.
  • Implementing IDisposable but not making Dispose idempotent — second call should be safe.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…