소멸자
소멸자
소멸자는 C++처럼 인수없는 생성자에 ~가 붙어 있는 형태이지만 프로그래머가 소멸자가 호출되는 시점을 제어할 수 없기 때문에 C++에서 소멸자를 사용했던 것만큼은 유용하지 않다. 소멸자는 사용자 코드에서 직접 호출할 수 없고 가비지 컬렉터에 의해 호출이 된다. 즉, 소멸자는 컴파일러에 의해 묵시적으로 Finalize 메소드로 재명명되고 가비지 컬렉터는 객체를 회수하기 전에 객체의 Finalize 메소드를 호출하여 리소스를 해제하거나 정리 작업을 수행할 수 있게 한다. 메모리 리소스는 가비지 컬렉터가 자체적으로 관리하지만, 비관리 리소스 (윈도우 핸들, 그래픽 핸들, OS 파일 핸들, 비관리 메모리 청크, 비관리 데이터베이스 커넥션 등)는 가비지 컬렉터가 처리하지 않는다. 이러한 리소스에 대해서는 자체적으로 회수해야 하는데 이러한 작업을 수행할 적당한 위치가 바로 소멸자이다. 참고로, C#에서는 Finalize 메소드를 직접 재정의 (override)할 수 없고 소멸자를 통해서 간접적으로 재정의 해야 한다. C#에서 비관리 리소스가 사용되는 경우는 PInvoke 서비스를 통하여 관리코드에서 비관리코드 (예: Windows 32 API)를 호출하는 경우나 System.Runtime.InteropServices.Marshall 클래스를 이용하여 관리되지 않는 메모리를 할당하고, 관리되지 않는 메모리 블록을 복사하고, 관리되는 형식을 관리되지 않는 형식으로 변환하고 비관리 코드와 상호 작용할 때 사용되는 기타 메서드을 사용할 경우이다.
using System;
public class MyResource
{
~MyResource()
{
// 비관리 리소스 정리 (clean up) 작업
// ...
// 소멸 시 비프음 발생 (테스트 목적)
Console.Beep();
}
}
public class DestructorExample
{
public static void Main()
{
Console.WriteLine ("엔터키를 입력하시오“);
Console.ReadLine();
MyResource res = new MyResource();
}
}
단순히 소멸자 부분에만 리소스를 환원하는 코드를 넣을 경우는 가비지 컬렉터가 언제 객체를 환원할지 알 수가 없어서 즉시 비관리 리소스를 환원해야 할 경우 (예를 들어, 파일이나 데이터베이스 핸들 같은 경우는 가비지 컬렉션이 발생하기를 기다리기 보다는 즉시 환원하는 것이 좋음)에는 문제가 될 수 있다. 이러한 경우는 IDisposable 인터페이스의 Dispose 메소드를 구현하고 이 메소드 안에 비관리 코드를 환원하는 코드를 넣으면 된다. 환원할 리소스를 갖고 있는 객체들은 이러한 약속에 따라 설계되기 때문에 리소스를 환원하고 싶으면 원하는 시점에서 Dispose 메소드를 명시적으로 호출해 주면 된다. Dispose 메소드에 대한 설명은 Interface 부분에서 자세히 설명토록 하겠다.