The “using declaration” introduced in C# 8.0 is a feature that drastically simplifies the syntax for resource management.
With traditional using statements, the code readability often suffered due to deep nesting caused by { ... } blocks. By utilizing using declarations, you can extend the variable’s scope to the entire block and implement safe Dispose processing without increasing indentation levels.
In this article, we will use a CSV file reading process as an example to explain the differences between the traditional notation and the new using declaration, as well as how it behaves.
Overview of using Declarations
A using declaration is a syntax where you simply add the using keyword when declaring a variable. This ensures that the variable is automatically Disposed when it goes out of scope.
The Traditional Problem (using Statement)
In the traditional writing style, curly braces {} were necessary to define the lifespan of the resource. If there were multiple resources, the nesting tended to get deep.
// Traditional style
using (var reader = new StreamReader("path/to/file.csv"))
{
// Indentation gets deep here
while (!reader.EndOfStream)
{
// Processing...
}
} // Disposed here
The New Solution (using Declaration)
With using declarations, you only need to add using to the variable definition line. Curly braces are not required.
// New style
using var reader = new StreamReader("path/to/file.csv");
// Indentation does not get deeper
while (!reader.EndOfStream)
{
// Processing...
}
// Automatically Disposed when the method (or current block) ends
Practical Code Example: Reading CSV Data
The following code is an implementation example of a method that reads a CSV file at a specified path and outputs its content to the console. It uses the using declaration to manage the file stream concisely.
using System;
using System.IO;
namespace DataProcessor
{
class Program
{
static void Main()
{
string filePath = "employees.csv";
// Create a file (for testing purposes)
File.WriteAllText(filePath, "ID,Name,Department\n101,Yamada,Sales\n102,Sato,Dev");
try
{
ReadAndPrintCsv(filePath);
}
catch (IOException ex)
{
Console.WriteLine($"File reading error: {ex.Message}");
}
}
/// <summary>
/// Reads a CSV file and displays the content.
/// Uses using declaration for resource management.
/// </summary>
static void ReadAndPrintCsv(string path)
{
if (!File.Exists(path))
{
Console.WriteLine("File does not exist.");
return;
}
Console.WriteLine($"--- Started reading {path} ---");
// [Point] using declaration
// This reader object is automatically Disposed (released)
// the moment we exit the ReadAndPrintCsv method.
using var reader = new StreamReader(path);
// Skip the header line
string header = reader.ReadLine();
Console.WriteLine($"Header: {header}");
// Read data lines
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line)) continue;
var columns = line.Split(',');
Console.WriteLine($"ID: {columns[0]}, Name: {columns[1]}, Dept: {columns[2]}");
}
Console.WriteLine("--- Reading complete ---");
// reader.Dispose() is implicitly called here (at the end of the method).
}
}
}
Execution Result
--- Started reading employees.csv ---
Header: ID,Name,Department
ID: 101, Name: Yamada, Dept: Sales
ID: 102, Name: Sato, Dept: Dev
--- Reading complete ---
Technical Points and Precautions
1. Timing of Resource Release
The lifespan (scope) of a variable defined with a using declaration lasts until the end of the block where that variable was declared. In the example above, it is released at the end of the method. However, if declared inside an if statement or for loop block, it will be released the moment that block is exited.
2. Improving Readability with Multiple Resources
When handling multiple IDisposable objects, such as a database connection (SqlConnection) and a command (SqlCommand), the effect of using declarations is significant.
Traditional:
using (var conn = new SqlConnection(...))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
// Deep nesting
}
}
Using Declaration:
using var conn = new SqlConnection(...);
conn.Open();
using var cmd = conn.CreateCommand();
// Can be written flat
3. When Explicit Scope is Needed
If you do not want to hold the resource until the end of the method and want to release it earlier, use the traditional using statement (block method) or explicitly create a scope with { } and place the using declaration inside it.
{
using var tempReader = new StreamReader("temp.txt");
// Processing...
} // Released here
// Subsequent long processing...
Summary
The using declaration has become one of the best practices for resource management in C#. Since it keeps code nesting shallow and improves readability, it is recommended to actively use using declarations whenever the variable’s scope (lifespan) can safely span the entire method.
