- 객체 중에는 열린 파일이나 자물쇠(lock), 운영체제 핸들, 비관리(unmanaged) 객체 같은 자원들을 해제하는 명시적인 해체(tear-down) 코드가 필요한 객체들이 있다. .NET의 어법에서 그런 작업을 처분(disposal)이라고 부른다.
- 처분은 쓰레기 수거(garbage collection, GC)와는 다른 연산이다. 보통의 경우 처분은 프로그래머가 명시적으로 수행하지만, 쓰레기 수거는 런타임이 자동으로 수행해준다.
IDisposable, Dispose, Close
- .NET Framework는 해체 수단이 필요한 형식을 위해 다음과 같은 특별한 인터페이스를 제공한다.
public interface IDisposable
{
void Dispose();
}
- C#의 using 문은 이 IDisposable을 구현하는 객체에 대해 Dispose 메서드를 try/finally 블록을 이용해서 호출하는 코드를 단축 표기하는 수단이라 할 수 있다. 예컨대 C# 컴파일러는 다음 코드를
using (FileStream fs = new FileStream("myFile.txt", FileMode.Open))
{
// ...
}
FileStream fs = new FileStream("myFile.txt", FileMode.Open);
try
{
// ...
}
finally
{
if (fs != null) ((IDisposable)fs).Dispose();
}
- finally 블록 덕분에, 예외가 발생하거나 기타 이유로 코드가 try 블록을 일찍 벗어날 때도 Dispose 메서드가 반드시 호출된다.
- 간단한 시나리오에서는 그냥 IDisposable을 상속해서 Dispose를 구현하기만 하면 처분 가능(disposal) 형식이 된다.
sealed class Demo : IDisposable
{
public void Dispose()
{
// 마무리/해체 작업을 수행한다.
}
}
표준 처분 의미론
- .NET Framework이 정의하는 형식들의 처분 논리는 ‘사실상의 표준’이라고 할 수 있는 특정한 규칙들을 따른다. 그 규칙들이 .NET Framework나 C# 언어의 명세에 포함되어 있는 것은 아니다. 그 규칙들은 단지 소비자들을 위한 일관된 프로토콜을 정의하기 위한 것일 뿐이다. 그 규칙들은 다음과 같다.
Close와 Stop
- 어떤 형식은 Dispose 외에 Close라는 메서드도 정의한다. 이 Close 메서드의 의미론에 관해 .NET Framework가 철저하게 일관적이지는 않지만, 거의 모든 경우 Close 메서드는 다음 둘 중 하나를 수행한다.
- 후자의 예는 IDbConnection이다. Close를 호출해서 연결을 닫은 후에 Open으로 다시 여는 것이 가능하다. 그러나 Dispose로 처분한 연결을 다시 살리지는 못한다.
- 어떤 클래스는 Stop 메서드를 정의한다 (예컨대 Timer나 HttpListener 클래스) Stop 메서드도 Dispose처럼 비관리 자원들을 해제할 수 있지만, Dispose와는 달리 Start 메서드로 객체의 작동을 다시 시작하는 것이 가능하다.
- WinRT(Windows Runtime)에서는 Close가 Dispose와 같은 것으로 간주된다. 실제로 WinRT 런타임은 Close라는 이름의 메서드들을 Dispose라는 이름의 메서드로 투영하는데, 이는 해당 형식들을 using 문에서 사용할 수 있게 하기 위한 것이다.