C# Destructor를 사용하지 못하는 struct

[제목] C# Destructor를 사용하지 못하는 struct

C# 클래스에서 소멸자(Destructor)는 소위 Unmanaged 리소스를 Clean up하기 위해 사용된다. 그렇다면, class가 아닌 struct 에도 Destructor를 사용할 수 있을까?

예를 들어, 다음과 같은 코드는 올바른 코드인가?

struct Area 
{
   public int Width;
   public int Height;

   public Area(int w, int h) {
       Width = w;
       Height = h;
    }

    ~Area() { }
}
이 코드를 컴파일하면 에러가 발생한다. 왜냐하면, struct는 ~Area()와 같은 Destructor를 사용할 수 없기 때문이다. 그렇다면, 만약 struct안에 SqlConnection이나 File 핸들같은 Unmanaged 리소스를 사용하면 어떻게 되는가?
struct MyStruct
{
    public string Data;
    private SqlConnection conn;
    const string cnStr = "Data Source=(local);Integrated Security=true;Initial Catalog=MyDB;";

    public MyStruct(string data)
    {
        this.Data = data;
        conn = new SqlConnection(cnStr);
        conn.Open();
    }

    public void Save()
    {
        string sql = "insert T1 values('" + Data + "')";
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.ExecuteNonQuery();
    }
}

void Test()
{
     MyStruct s = new MyStruct("test");
     s.Save();
}

위의 문장은 문제없이 컴파일되고 실행된다. 하지만, 자세히 보면, SqlConnection 객체인 conn 이 해제(Close)되지 않았다. 이것이 의미하는 것은 SQL 서버 상에는 계속 Connection이 남아 있다는 것이고, 프로그램이 종료될 때까지 계속 연결이 끊기지 않는다는 것이다.

이러한 Leak 현상을 막기 위해 C# 클래스를 구현할 때 IDisposable 인터페이스를 구현하고 사용자가 Dispose를 사용하도록 하고 하고, 만약 Dispose()를 사용하지 않는 경우 최후의 보루로 Destructor가 실행되도록 한다. 하지만, struct는 Destructor를 구현할 수 없다. Destructor는 .NET의 Garbage Collector(GC)와 밀접한 관련이 있는데, GC가 객체를 완전 소멸시키기 전에 호출하는 것이 Destructor이다.

struct는 Value Type으로 (보통) 스택에 생성되며 GC가 관리하지 않는다. 따라서 Destructor를 사용할 필요가 없다. C#에서 struct를 지원하는 이유는 단순한 데이타를 스택에서 신속하게 사용하기 위해서이다. 좀 더 일반화 하면, class를 사용할 때와 struct를 사용할 때가 서로 다른 것이다. 위의 SqlConnection을 사용한 예제는 다소 극단적인(?) 예를 든 것이고, 물론 위의 경우 struct 대신 class를 사용하는 것이 맞는 방식이다.



본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.