본문 바로가기
C#/Effective C#

[Effectvie C#] Item 46 리소스 정리를 위해 using과 try/finally를 활용하라

by 코모's 2023. 6. 12.
반응형

관리되지 않은 시스템 리소스를 사용하는 타입은 IDisposable 인터페이스의 Dispose() 메서드를 이용하여 일시적으로 리소스를 해제해야한다.

사용자 입장에서 Dispose() 메서드가 항상 호출되도록 코드를 작성하기 위한 최선의 방법은 using문이나 try/finally 블록을 활용하는 것이다.

 

using 문 사용하기

다음과 같은 코드를 작성했다고 해보자.

public void ExecuteCommand(string connString, string commandString)
{
	SqlConnection myConnection = new SqlConnection(connString);
    var mySqlCommand = new SqlCommand(commandString, myConnection)l
    myConnection.Open();
    mySqlCommand.ExcuteNonQuery();
}

SqlConnection과 SqlCommand는 둘다 Dispose()를 구현한 객체지만 사용자가 Dispose()를 호출하지 않았기 때문에 finalizer가 호출될 때 까지 메모리에 남게된다.

 

그렇다면 직접 호출하면 해결될까??

public void ExecuteCommand(stirng connString, String commandString)
{
	var myConnection = new SqlConnection(connString);
    var mySqlCommand = new SqlCommand(commandString, myConnection);
    MyConnection.Open();
    mySqlCommand.ExecuteNonQuery();
    
    mySqlCommand.Dispose();
    myConnection.Dispose();
}

하지만 이건 sql 명령 실행 중 어떠한 예외도 발생하지 않앗을 때 유효하다.

 

때문에 이 경우 using 문 내에서 객체를 할당하면 C# 컴파일러가 해당 객체에 대해 try/finally 블록을 자동으로 생성하여 항상 Dispose() 가 호출되도록 해준다.

 

public void ExecuteCommand(string connString, string commandString)
{
	using(SqlConnection myConnection = new SqlConnection(connString))
    {
    	using(SqlCommand mySqlCommand = new SqlCommand(commandString, myconnection))
        {
        	myConnection.Open();
            mySqlCommand.ExcuteNonQuery();
        }
    }
}

 

using문 사용하기

단, IDisposable 인터페이스를 지원하지 않는 타입에 대해서 using문을 사용하면 컴파일 에러가 발생한다.

obj는 IDisposable인터페이스를 지원하지 않기 때문에 아래의 코드는 컴파일되지 않는다.

using(object obj = Factory.CreateResource())
	Console.WriteLine(obj.ToString());

이경우 as를 이용하면 타입이 IDisposable을 실제로 구현했는지와 관계없이 안전하게 코드를 작성할 수 있다.

object obj = Factory.CreateResouce();
using(obj as IDisposable)
	Console.WriteLine(obj.ToString());

 

중첩된 using문 피하기

public void ExecuteCommand(stirng conneString, string commandString)
{
	SqlConnection myConnection = null;
    sqlCommand mySqlCommand = null;
    
    try
    {
    	myConnection = new SqlConnection(connString);
        mySqlCommand = new SqlCommand(commandString, myConnection);
        myConnection.Open();
        mySqlCommand.ExecuteNonQuery()l
    }
    finally
    {
    	if(mySqlCommand != null)
        	mySqlCommand.Dispose();
        if(myConnection != null)
        	myConnection.Dispose();        
    }
}

 

결론

IDisposable타입을 사용할때는 어떤 경우라도 올바르게 Dispose() 메서드가 호출될 수 있도록 코드를 작성해야 한다. 

 

반응형