C#/Effective C#

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

코모's 2023. 6. 12. 16:43
반응형

관리되지 않은 시스템 리소스를 사용하는 타입은 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() 메서드가 호출될 수 있도록 코드를 작성해야 한다. 

 

반응형