using 문 - 삭제 가능한 객체를 올바르게 사용하기
using 문 - 삭제 가능한 객체를 올바르게 사용하기
using 문은 xref:System.IDisposable 인스턴스를 올바르게 사용하도록 보장해요. 파일이나 네트워크 연결처럼 다 쓰고 나면 꼭 정리해야 하는 객체를 다룰 때, "썼으면 반드시 닫아야 한다"는 규칙을 컴파일러가 지켜주도록 하는 장치예요.
출처: Microsoft Learn
본문
var numbers = new List<int>();
using (StreamReader reader = File.OpenText("numbers.txt"))
{
string line;
while ((line = reader.ReadLine()) is not null)
{
if (int.TryParse(line, out int number))
{
numbers.Add(number);
}
}
}
using 문의 블록을 벗어나는 순간, 획득한 xref:System.IDisposable 인스턴스는 해제(dispose)돼요. 특히 이 문은 블록 안에서 예외가 발생해도 삭제 가능한(disposable) 인스턴스가 반드시 해제되도록 보장해 줍니다. 위 예시에서는 모든 줄을 처리한 뒤에 열어 둔 파일이 닫히죠.
xref:System.IAsyncDisposable 인스턴스를 올바르게 쓰려면 await using 문을 사용해요.
await using (var resource = new AsyncDisposableExample())
{
// Use the resource
}
xref:System.IAsyncDisposable 인스턴스 사용에 대한 더 자세한 내용은 DisposeAsync 메서드 구현 문서의 비동기 삭제 가능 객체 사용 섹션을 참고하세요.
중괄호가 필요 없는 using 선언 형태도 쓸 수 있어요.
static IEnumerable<int> LoadNumbers(string filePath)
{
using StreamReader reader = File.OpenText(filePath);
var numbers = new List<int>();
string line;
while ((line = reader.ReadLine()) is not null)
{
if (int.TryParse(line, out int number))
{
numbers.Add(number);
}
}
return numbers;
}
using 선언으로 선언된 지역 변수는 그 변수가 선언된 스코프가 끝나는 지점에서 해제됩니다. 위 예시에서는 메서드가 끝날 때 해제가 일어나요.
참고로 using 문이나 선언으로 만든 변수는 readonly예요. 다시 대입할 수도 없고, ref나 out 매개 변수로 넘길 수도 없습니다.
같은 타입의 인스턴스 여러 개를 하나의 using 문에 선언할 수도 있어요.
using (StreamReader numbersFile = File.OpenText("numbers.txt"), wordsFile = File.OpenText("words.txt"))
{
// Process both files
}
하나의 using 문에 여러 인스턴스를 선언하면, 선언한 순서의 반대로 해제됩니다.
using 문과 선언은 삭제 가능 패턴에 맞는 ref struct 인스턴스에도 쓸 수 있어요. 즉, 접근 가능하고 매개 변수가 없으며 void를 반환하는 인스턴스 Dispose 메서드를 가진 경우를 말합니다.
using 블록 안에서 return을 해도 해제는 보장됩니다. 컴파일러가 이를 try/finally로 다시 작성하므로, 메서드가 실제로 반환되기 전에 리소스의 Dispose가 항상 호출되거든요.
using 문은 다음 형태로도 쓸 수 있습니다.
using (expression)
{
// ...
}
여기서 expression은 삭제 가능한 인스턴스를 만들어 내요. 다음 예시가 바로 그 형태를 보여줍니다.
StreamReader reader = File.OpenText(filePath);
using (reader)
{
// Process file content
}
[!WARNING] 위 예시에서
using문을 벗어난 뒤에도 삭제 가능한 인스턴스는 이미 해제된 채 스코프 안에 남아 있어요. 이 인스턴스를 계속 사용하면 xref:System.ObjectDisposedException 같은 예외가 발생할 수 있습니다. 그래서 삭제 가능한 변수는using문 안에 선언하거나using선언으로 만들기를 권해요.