C#
error-handling
programming
.NET
code-practices

'using' statement vs 'try finally'

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In C#, using and try/finally solve the same resource-management problem: they make sure cleanup happens even when the code exits early or throws an exception. The difference is that using is a specialized language feature for IDisposable objects, while try/finally is the more general control-flow tool that using effectively expands into.

What using really does

When you write a using block, the compiler generates logic that calls Dispose() in a finally block. That is why using is usually preferred for files, streams, database connections, and other disposable resources.

csharp
1using System;
2using System.IO;
3
4class Program
5{
6    static void Main()
7    {
8        using (var writer = new StreamWriter("log.txt"))
9        {
10            writer.WriteLine("hello");
11        }
12    }
13}

The cleanup is deterministic. As soon as execution leaves the block, Dispose() runs.

The equivalent try/finally form

The same logic can be written manually with try/finally.

csharp
1using System;
2using System.IO;
3
4class Program
5{
6    static void Main()
7    {
8        StreamWriter writer = new StreamWriter("log.txt");
9        try
10        {
11            writer.WriteLine("hello");
12        }
13        finally
14        {
15            writer.Dispose();
16        }
17    }
18}

This is more verbose, but it makes the relationship clear: using is the concise form for a common try/finally pattern.

Why using is usually the better choice

For straightforward disposal, using communicates intent immediately. A reader can see that the object is scoped to a block and will be cleaned up automatically. That reduces boilerplate and lowers the chance of forgetting to call Dispose().

Modern C# also supports using var, which shortens the syntax even further.

csharp
1using System;
2using System.IO;
3
4class Program
5{
6    static void Main()
7    {
8        using var writer = new StreamWriter("log.txt");
9        writer.WriteLine("hello");
10    }
11}

The object is disposed at the end of the enclosing scope.

When try/finally is still the right tool

try/finally is still useful when cleanup is not just Dispose(), when multiple pieces of cleanup must happen in a specific order, or when the resource lifetime does not match a neat lexical block.

For example, you may need to set a flag before a section of code and restore it afterward regardless of success or failure.

csharp
1bool oldValue = Console.CursorVisible;
2try
3{
4    Console.CursorVisible = false;
5    Console.WriteLine("Working...");
6}
7finally
8{
9    Console.CursorVisible = oldValue;
10}

That is not a using problem. It is general cleanup logic, which is exactly what finally is for.

using does not replace exception handling

Another common misunderstanding is treating using as an error-handling feature. It is not. using guarantees disposal, but it does not catch exceptions for you. If you need to handle an error and also dispose of a resource, combine using with try/catch.

That separation of responsibilities is useful:

  • 'using controls resource lifetime.'
  • 'catch handles errors.'
  • 'finally handles cleanup that is not naturally modeled as IDisposable.'

Choose based on the cleanup model

If you are disposing an IDisposable within a clear scope, use using. If you need broader, custom, or non-disposable cleanup logic, use try/finally. If both are true, combine them instead of forcing one construct to do the other's job.

That is the practical rule most teams follow.

Common Pitfalls

  • Writing manual try/finally disposal everywhere when a simple using block would be clearer.
  • Assuming using catches exceptions instead of only ensuring disposal.
  • Holding a disposable object longer than necessary by giving it a scope that is too wide.
  • Forgetting that try/finally is still needed for cleanup that is not based on IDisposable.
  • Disposing resources manually inside a using block and making the lifetime harder to reason about.

Summary

  • 'using is specialized syntax for deterministic disposal of IDisposable resources.'
  • It effectively compiles down to a try/finally cleanup pattern.
  • Use using for normal disposable resources such as streams and database connections.
  • Use try/finally for custom cleanup that is not just Dispose().
  • Combine using with catch when you need both disposal and explicit error handling.

Course illustration
Course illustration

All Rights Reserved.