Using vs. Try-Finally
Part of the Logic & Flow section of Coddy's C# journey — lesson 28 of 66.
Both using statements and try-finally blocks help manage resources that need to be properly disposed of. The using statement provides a cleaner, more concise way to ensure that IDisposable objects are properly cleaned up.
Let's look at a try-finally approach first. Here, StreamReader is a class that reads text from a file — it holds an open file handle, which is a resource that must be released when we're done:
StreamReader reader = null;
try
{
reader = new StreamReader("file.txt");
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
finally
{
if (reader != null)
{
reader.Dispose();
}
}
The finally block guarantees that Dispose() is called to release the file handle, even if an exception occurs inside the try block.
The using statement simplifies this pattern. It declares and initializes the resource in parentheses, and automatically calls Dispose() when the block exits — whether normally or due to an exception:
using (StreamReader reader = new StreamReader("file.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
This is equivalent to the try-finally example above, but with less boilerplate code.
The using statement automatically calls Dispose() when the block exits, even if an exception occurs. It replaces the try-finally cleanup pattern — not try-catch. If you also need to handle exceptions, you can still wrap a using block inside a try-catch.
Challenge
EasyCreate a method named processFile that:
- Takes a filename as a string parameter
- Uses the
usingstatement with aStreamReaderto read all lines from the file - Returns the number of lines in the file
- If a
FileNotFoundExceptionoccurs, print "File not found" and return -1
Cheat sheet
The using statement provides automatic resource cleanup for IDisposable objects, ensuring Dispose() is called even if exceptions occur. It replaces the verbose try-finally pattern.
Try-finally approach:
StreamReader reader = null;
try
{
reader = new StreamReader("file.txt");
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
finally
{
if (reader != null)
{
reader.Dispose();
}
}
Using statement (cleaner approach):
using (StreamReader reader = new StreamReader("file.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
Both approaches ensure Dispose() is called when the block exits. The using statement handles this automatically, removing the need for a manual null check and finally block.
Key points:
• using replaces try-finally — not try-catch
• try-catch can still be combined with using to handle exceptions
• StreamReader reads text files and implements IDisposable, making it ideal for use with using
Try it yourself
using System;
using System.IO;
class ProcessFile
{
public static int processFile(string filename)
{
// Write your code here
}
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Logic & Flow
1Multi-dimensional Arrays
2D Arrays BasicsDeclaring and Initializing 2DAccessing 2D Array ElementsNested Loops with 2D ArraysJagged ArraysCommon Matrix OperationsRecap - Multi-dimensional4Flow Control Techniques
Early ReturnsGuard ClausesJump Statements (goto)Break and ContinueFlatten Nested Conditionals7Logical Operators Advanced
Short-Circuit EvaluationConditional Logical OperatorsOperator PrecedenceRecap - Advanced Operators2Advanced Decision Making
Multiple ConditionsComplex Boolean LogicIf vs. Switch ComparisonNested Switch StatementsRecap - Advanced Decisions5Exception Handling
Try-Catch BasicsException TypesMultiple Catch BlocksWorking with FilesFinally BlockUsing vs. Try-FinallyCustom ExceptionsRecap - Error Handling3Loop Enhancements
Loop PerformanceIterating ComplexEach Loop TypeRefactoring LoopsRecap - Optimized Loops6Null Handling
Null Reference BasicsNullable Value TypesNull Checking PatternsDefensive ProgrammingRecap - Null Safety