04
27
다음 본문은 도서 이펙티브 C# (빌 와그너)에서 나오는 주제를 다룹니다.

 

 

 

제약조건은 타입 매개변수가 할 수 있는 것을 규정하지만, 무엇을 해서는 안 되는지는 규정하지 않는다. 

제약조건이 요구하는 작업 외에는 신경을 쓰지 않는다는 것이다.

 

하지만 IDisposable을 구현하고 있다면 추가 작업이 필요하다.

 

메소드 내에서 타입 객체를 생성한 경우

 - T가 IDisposable을 구현한 타입일경우 그냥 생성하고 사용하기만하면 리소스 누수가 발생할 수 있다. 

 - T가 IDisposable을 구현했다면 using 블록이 끝날 때 Dispose()를 호출한다.

public void GetThingsDone()
{
    T driver = new T();
    using(driver as IDisposable)
    {
        diriver.DoWork();
    }
}

 

클래스 내의 멤버로 타입 객체를 선언한경우

 - T가 IDisposable을 구현했을 가능성이 있다면 클래스 내에서 IDisposable을 구현하여 해당 리소스를 처리해야한다.

public sealed class EngineDriver2<T> : IDisposable where T : IEngine, new()
{
    private Lazy<T> driver = new Lazy<T>(() => new T());
    
    public void GetThingsDone() => driver.Value.Dowork();
    
    public void Dispose()
    {
        if(driver.IsValueCreated)
        {
            var resource = driver.Value as IDisposable;
            resource?.Dispose();
        }
    }
}

 - 제네릭 클래스의 코드가 복잡해 지는 것을 원하지 않는다면, 객체의 소유권과 Dispose의 호출책임을 외부로 넘겨 new() 제약조건을 제거할 수 있다.

public sealsed class EngineDriver<T> where T : IEngine
{
    private T driver;
    
    public EngineDriver(T driver)
    {
        this.driver = driver;
    }
    
    public void GetThingsDone()
    {
        driver.DoWork();
    }
}

 

결론

 - 타입 매개변수를 사용하는 경우 리소스가 누수되지않도록 주의하자.

 

 

COMMENT