色んな事を書く

シンプルさを極めたエンジニアになりたい

IDisposable を実装したクラスを DI Container で使うとき Dispose はいつ呼ばれるのか

備忘用のメモです。

結論、インスタンスが破棄される時です。DI Container で生成されたインスタンスのライフサイクルは DI Container で管理されるので、破棄のタイミングで Dispose を呼び出してくれるみたいです。

雑にサンプルコード。DI Container に登録した Service の有効期限が異なり、IDspoable を実装したクラスを 3 つ用意します。

public class SingletonSample: IDisposable
{
    public void Dispose()
    {
        Console.WriteLine($"Disposing {nameof(SingletonSample)}");
        GC.SuppressFinalize(this);
    }
}

public class ScopedSample: IDisposable
{
    public void Dispose()
    {
        Console.WriteLine($"Disposing {nameof(ScopedSample)}");
        GC.SuppressFinalize(this);
    }
}

public class TransientSample: IDisposable
{
    public void Dispose()
    {
        Console.WriteLine($"Disposing {nameof(TransientSample)}");
        GC.SuppressFinalize(this);
    }
}

んで、これらを使う側のコード

public class DisposeController: ControllerBase
{
    private readonly SingletonSample _singletonSample;
    private readonly ScopedSample _scopedSample;
    private readonly TransientSample _transientSample;
    private readonly DependentObject _dependentObject;
    
    public DisposeController(
        SingletonSample singletonSample,
        ScopedSample scopedSample,
        TransientSample transientSample,
        DependentObject dependentObject)
    {
        _singletonSample = singletonSample;
        _scopedSample = scopedSample;
        _transientSample = transientSample;
        _dependentObject = dependentObject;
    }
    
    [HttpGet]
    public IActionResult Get()
    {
        Console.WriteLine("Finish processing request");
        return Ok();
    }
}

Transient の挙動を見るためのオブジェクト。

public class DependentObject
{
    private readonly SingletonSample _singletonSample;
    private readonly ScopedSample _scopedSample;
    private readonly TransientSample _transientSample;
    
    public DependentObject(
        SingletonSample singletonSample,
        ScopedSample scopedSample,
        TransientSample transientSample)
    {
        _singletonSample = singletonSample;
        _scopedSample = scopedSample;
        _transientSample = transientSample;
    }
}

これで (DI Container の登録は別途やってる) Controller のエンドポイントを叩くと以下のようになります (検証のため 2 回叩いています)。

Finish processing request
Disposing TransientSample
Disposing TransientSample
Disposing ScopedSample
Finish processing request
Disposing TransientSample
Disposing TransientSample
Disposing ScopedSample 

きちんと Controller の処理が終わって Dispose が呼び出されているようにみえますね。Scoped, Transient の有効期限も加味されていそうです。

ではこの状態でプロセスを終了させてみます。

info: Microsoft.Hosting.Lifetime[0]  
      Application is shutting down...
Disposing SingletonSample

Singleton で注入したサービスも Dispose が呼び出されてますね。

learn.microsoft.com