[C#] 5.1 캡슐화 대상(5.1.6 소멸자)

소멸자는 개체가 소멸할 때 수행해야 할 작업에 대한 코드 블록입니다. 소멸자는 클래스에서만 정의할 수가 있고 구조체에는 정의할 수 없습니다. C++에서는 동적으로 생성된 개체를 개발자가 소멸시켜야 합니다. 하지만 C#에서는 .NET 플랫폼의 가비지 수집기가 주기적으로 개체 수명을 조사를 통해 개체를 참조하는 변수가 없는 개체를 확인하고 정책에 의해 자동으로 소멸합니다.

이에 소멸자의 접근 한정자는 개발자가 명시할 수 없습니다. 그리고 다른 메서드들과 달리 중복 정의할 수도 없습니다. 소멸자의 이름은 형식 이름 앞에 ~가 붙습니다. 그리고 가비지 수집기가 소멸되는 시점에 자동으로 호출합니다.

class Man
{
    ~Man()
    {
        Console.WriteLine("소멸자");
    }
}

컴파일러는 소멸자를 정의하면 컴파일러에서는 Finalize 메서드를 호출하는 코드로 변환됩니다. ildasm 유틸리티를 이용하여 덤프해 보면 이를 확인하실 수 있습니다.

▶ildasm으로 덤프한 IL코드

.method family hidebysig virtual instance void 
        Finalize() cil managed
{
  // 코드 크기       25 (0x19)
  .maxstack  1
  .try
  {
    IL_0000:  nop
    IL_0001:  ldstr      bytearray (4C C7 )                                           // L.
    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000b:  nop
    IL_000c:  nop
    IL_000d:  leave.s    IL_0017
  }  // end .try
  finally
  {
    IL_000f:  ldarg.0
    IL_0010:  call       instance void [mscorlib]System.Object::Finalize()
    IL_0015:  nop
    IL_0016:  endfinally
  }  // end handler
  IL_0017:  nop
  IL_0018:  ret
} // end of method Man::Finalize
ildasm 유틸로 덤프한 화면
[그림 17] ildasm 유틸로 덤프한 화면

 이처럼 개발자가 소멸자를 정의하면 컴파일러에 의해 묵시적으로 Finalize 메서드로 변환이 되고 가비지 수집기로 개체가 소멸하는 작업을 수행하게 됩니다. 만약, 소멸하는 시점에 특별히 할 작업이 없는데도 비어있는 소멸자를 정의하면 비어있는 Finalize 메서드를 수행하게 됩니다. 따라서 비어있는 소멸자는 정의하지 마시기 바랍니다.

또한, 외부 자원을 사용하는 경우에 명시적으로 자원 해제를 원한다면 Dispose 메서드를 정의하여 성능을 높일 수 있습니다.

▶ IDisposable 인터페이스 기반의 클래스 정의

class Man:IDisposable
{
    bool isdispose;
    ~Man()
    {
        Dispose();
    }
    public void Dispose()
    {
        if ( ! isdispose )
        {
            //자원 해제 구문
        }
        isdispose = true;
    }
}