Machineboy空

C# 자원 해제(Resource Clean up) try~catch, finally, using Dipose() 본문

언어/C#

C# 자원 해제(Resource Clean up) try~catch, finally, using Dipose()

안녕도라 2025. 2. 26. 18:35

IDisposable을 활용한 resource-cleanup 자원해제

  • use the IDipose interface to signal that some object's resource or other program state needed to be released or reset when the object was no longer required
  • relying on the garbage collector would not achieve this or provide the required level of control

가비지 컬렉터

  • 더 이상 사용되지 않는 객체를 자동으로 메모리에서 제거하는 역할.
  • 메모리 누수를 방지하고 사용가능한 메모리를 확보할 수 있다.

하지만 이러한 가비지 컬렉터는 데이터 베이스 연결이나, 네트워크 소켓, 파일 핸들 등의 비메모리 리소스는 해제하지 않는다.

이럴 때 직접 해제를 하기 위해 IDisposable을 활용!


finally

try블록에서 코드를 실행하다가 예외가 던져지면 프로그램의 실행이 catch절로 바로 넘어온다.

try블록 내에서 자원 해제 같은 중요한 코드를 미처 실행하지 못하고 catch절로 넘어가면 버그를 만드는 원인이 된다.

try {
	dbconn.Open(); 	// dbconn은 데이터베이스 커넥션
}
catch(XXXException e){
	
}
finally {
	dbconn.Close();	// dbconn 해제
}

 

자신이 소속된 try절이 실행된다면 finally절은 어떠한 경우라도 실행된다.


using 과 Dispose()

파일을 열어서 실컷 이용한 다음, 자원을 해제하지 않는 실수를 자주 한다.

이러한 실수를 방지하기 위한 것이 using선언이다.

 

using선언을 통해 코드 블록의 마지막에서 Dispose() 메소드가 호출되도록 한다.

Stream.Close() 메소드가 IDisposable 인터페이스에서 상속받은 Dispose()메소드를 호출하기 때문이다

 

  • using문에서 사용하는 변수: IDisposable 인터페이스를 구현한 참조형(Reference Type)이어야 한다.
{
	// 1. 파일 스트림 열기
	using Stream outStream = new FileStream("a.dot", FileMode.Create);
    
    // 2. someValue(long 형식)을 byte배열로 변환
    byte[] wBytes = BitConverter.GetBytes(someValue);
    
    // 3. 변환한 byte 배열을 파일 스트림을 통해 파일 기록
    outStrea,.Write(wByte, 0, wByte.Length);
}

 

using을 쓰는 두가지 패턴

// 첫번째 패턴
using(var file = new File("my_secrets"))
{
	filet.WriteSecret("xxxxxxx");
}

// 두번째 패턴

using var drawingResource = some_provided_or_new_object;

try
{
	drawingResource.DrawSomething();
}
catch (Exception)
{
	throw;
}

Dispose()

provide an opportunity for unmanaged resources such as operating system objects to be released and the internal state of managed resources to be reset.


예제1

public class Orm : IDisposable	// IDisposable 인터페이스 상속
{
    private Database database;
    

    public Orm(Database database)
    {
        this.database = database;
    }

    public void Begin()
    {
        database.BeginTransaction(); // State.TransactionStarted로 변경
    }

    public void Write(string data)
    {
        try			// State.DataWritten 상태로 변경
        {
            database.Write(data);
        }
        catch		// State.Close상태에서 Write하려고 할 때 자원 해제
        {
            database.Dispose(); 
            
        }
    }

    public void Commit()
    {
        try
        {
            database.EndTransaction(); // State.Closed로 변경
        }
        catch
        {
            database.Dispose();	// 이미 State.Closed상태라면!
        }
    }

    public void Dispose()
    {
        database.Dispose();
    }
}

 

https://exercism.org/tracks/csharp/exercises/object-relational-mapping/edit

 

Exercism

Learn, practice and get world-class mentoring in over 50 languages. 100% free.

exercism.org

 


예제2

public class Orm
{
    private readonly Database database;

    public Orm(Database database)
    {
        this.database = database;
    }

    public void Write(string data)
    {
        using (database)  // Dispose()가 자동 호출되도록 설정
        {
            database.BeginTransaction();
            database.Write(data);
            database.EndTransaction();
        }
    }

    public bool WriteSafely(string data)
    {
        try
        {
            Write(data);
            return true;
        }
        catch
        {
            return false;
        }
    }
}

 

https://exercism.org/tracks/csharp/exercises/orm-in-one-go/edit

 

Exercism

Learn, practice and get world-class mentoring in over 50 languages. 100% free.

exercism.org