[C#] 클래스에서 ~(tilde)의 의미. 종료자란 무엇인가요? (파이널라이저, 소멸자)

이번 시간에는 클래스에서 생성자와 비슷한 메서드에 ~(tilde)가 무엇인지 알아보도록 하겠습니다. 결론부터 요약하며 말씀드리면, 해당 기호는 생성자의 반대말인 종료자(소멸자)를 뜻한답니다. 영문으로는 파이널라이저라고 합니다.

  • C# 클래스에서 ~(tilde)의 의미. 종료자란 무엇인가요?
  • C# 종료자(파이널라이저, 소멸자)

C# 클래스에서 ~(tilde)의 의미. 종료자란 무엇인가요?

클래스 이름과 동일한 메서드 이름은 많이 보셨을 겁니다. 생성자(constructor)이지요. 가끔 소스를 보면 이 생성자 앞에 물결표시(~ : tilde)가 붙어있는 것을 볼 수 있습니다. 틸더가 붙어있는 이 메서드는 사실 생성자가 아니라 종료자(또는 소멸자)를 뜻하며, 오늘의 주제는 이 종료자(파이널라이저 : finalizer)가 무엇인지 그 특징을 알아보는 시간입니다.

종료자가 무엇인가요? 특징 알아보기

  1. 종료자는 클래스에서만 사용합니다. 
  2. 종료자는 클래스 내에서 오직 하나.
  3. 종료자는 상속되지 않습니다.
  4. 종료자는 별도의 한정자가 없습니다.
  5. 종료자를 명시적으로 호출할 수 없습니다.

C# 종료자(파이널라이저, 소멸자)

C# 종료자

종료자는 클래스에서 사용

종료자는 클래스(class) 종료를 위해 사용되기에 구조체(structs)에서 정의할 수 없습니다.

struct Struct
{
    ~Struct()
    {

    }
}

=>
CS0575: 클래스 형식만 소멸자를 포함할 수 있습니다.

종료자는 클래스 내에서 오직 하나

종료자는 클래스에서 하나만 가질 수 있습니다. 생성자는 매개변수로 하여금 오버로딩이 가능하지만, 그와 반대로 종료자는 굳이 그럴 필요가 없기에 클래스 내에서 하나만 정의할 수 있습니다. 종료자는 별도의 매개변수가 없고, 오버로드도 없습니다.

~ChildClass()
{
    
}

~ChildClass(int i)
{

}

=>
CS0111: 'MainWindow.ChildClass' 형식은 동일한 매개 변수 형식을 가진 '~ChildClass' 멤버를 미리 정의합니다.

종료자는 상속되지 않습니다.

종료자는 오브젝트 객체의 파이널라이즈 메서드를 호출합니다. 별도의 상속이 존재하지 않기에 상속되지 않습니다.

종료자는 별도의 한정자가 없습니다.

클래스 내부, 외부 어디서든 호출 할 필요가 없기에 한정자가 없습니다.

private ~ChildClass()
{

}

=>
CS0106: 이 항목의 'private' 한정자가 유효하지 않습니다.

종료자를 명시적으로 호출할 수 없습니다.

종료자는 명시적 호출 대상이 아니고, 클래스 종료 시 자동으로 호출이 됩니다.

public ChildClass()
{
    ~ChildClass();
}

=>
CS0201: 대입, 호출, 증가, 감소 및 새 개체 식만 문으로 사용할 수 있습니다.
CS1955: 호출할 수 없는 멤버인 'MainWindow.ChildClass'은(는) 메서드처럼 사용할 수 없습니다.

종료자는 Object.Finalize 메서드를 호출합니다. 아래의 예제 자료는 상속과 오버로딩이 불가능한 종료자와 오버로딩이 가능한 생성자 비교 등을 안내해드리겠습니다. 아웃풋에서는 현재 호출 스택과 실행 메서드를 표시해드리겠습니다.

public class GrandparentClass
{
    ~GrandparentClass()
    {
        Debug.WriteLine("~GrandparentClass");
        Debug.WriteLine(MethodBase.GetCurrentMethod());
    }
}

public class ParentClass : GrandparentClass
{
    ~ParentClass()
    {
        Debug.WriteLine("~ParentClass");
        Debug.WriteLine(MethodBase.GetCurrentMethod());
    }
}

public class ChildClass : ParentClass
{
    int m_i = 0;
    public ChildClass()
    {

    }
    public ChildClass(int i)
    {
        m_i = i;
    }
    ~ChildClass()
    {
        Debug.WriteLine("~ChildClass");
        Debug.WriteLine(MethodBase.GetCurrentMethod());
    }
}

=> output
~ChildClass
Void Finalize()
~ParentClass
Void Finalize()
~GrandparentClass
Void Finalize()

댓글