관리되지 않은 시스템 리소스를 사용하는 타입은 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() 메서드가 호출될 수 있도록 코드를 작성해야 한다.
'C# > Effective C#' 카테고리의 다른 글
[Effective C#] Item48 강력한 예외 보증을 준수하는 것이 좋다. (0) | 2023.06.12 |
---|---|
[Effective C#] Item47 사용자 지정 예외 클래스를 완벽하게 작성하라 (0) | 2023.06.12 |
[Effectvie C#] Item 45 메서드가 실패했음을 알리기 위해서 예외를 이용하라 (0) | 2023.05.23 |
[Effective C#] Item 44 바인딩 된 변수는 수정하지 말라 (0) | 2023.05.23 |
[Effective C#] Item 43 쿼리 결과의 의미를 명확히 강제하고, Single()과 First()를 사용하라. (0) | 2023.05.11 |