はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【C#】非同期using(await using)を利用してIAsyncDisposableインターフェイスを実装するオブジェクトの破棄・解放処理を実行する

はじめに

今回は非同期using(await using)について紹介したいと思います。

learn.microsoft.com

概要

IAsyncDisposableを実装しているオブジェクトに対して、await usingを利用することで非同期な破棄処理を書くことができます。

private static async Task Sample()
{
    // 1 -> 2 -> 3
    await using (var exampleAsyncDisposable = new ExampleAsyncDisposable())
    {
        Console.WriteLine("1番目に呼ばれる");
    }
    Console.WriteLine("3番目に呼ばれる");

    // 2
    await using var exampleAsyncDisposable2 = new ExampleAsyncDisposable();
}

public sealed class ExampleAsyncDisposable : IAsyncDisposable
{
    public async ValueTask DisposeAsync()
    {
        // 破棄・解放処理を書く
        // ValueTaskを返すので、同期処理であったとしてもTaskのインスタンスがマネージドヒープに確保されない
        await Task.Delay(1000);
        Console.WriteLine("2番目に呼ばれる");
    }
}

また公式サンプルではConfigureAwait(false)を利用して、スレッドを元に戻らないようにしているようですね。(状況に応じて)

var exampleAsyncDisposable = new ExampleAsyncDisposable();
await using (exampleAsyncDisposable.ConfigureAwait(false))
{
    // Interact with the exampleAsyncDisposable instance.
}

Console.ReadLine();

必ずIAsyncDisposableを実装する必要はない

await usingはパターンベースらしく、必ずしもIAsyncDisposableを実装しなければならないわけではないようです。

非同期usingはパターン ベースになっています。 以下のように、IAsyncDisposableインターフェイスを実装せず、 単にDisposeAsyncメソッドを持っていればawait usingで使えます。

非同期ストリーム - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

返り値がawaitableなら良いっぽいです。以下Awaitableパターンの説明。
ufcpp.net

またclassではなくstructでもOKです。

IDisposableとIAsyncDisposable

通常、IAsyncDisposable インターフェイスを実装するとき、そのクラスでは IDisposable インターフェイスも実装します。 IAsyncDisposable インターフェイスの推奨される実装パターンは、同期か非同期のいずれかの破棄のために準備をすることです。 クラスの同期の破棄が不可能な場合は、IAsyncDisposable を持つことだけが許容されます。 破棄パターンの実装に関するガイダンスのすべての説明は、非同期の実装にも適用されます。

DisposeAsync メソッドの実装 | Microsoft Learn

IAsyncDisposableは非同期で破棄処理を書く必要がある可能性があるときに実装し、IAsyncDisposableを実装するならIDisposableも実装せよということらしいですね。

また混在している場合、どっちが呼ばれるかは以下の通り。

ちなみに、Dispose(IDisposableインターフェイス)とDisposeAsync(IAsyncDisposableインターフェイス)の両方を実装をしている場合、それぞれ同期版using、非同期usingでしか呼ばれません。 非同期版が同期版を兼ねたりはしませんし、その逆もまたしかり。

非同期ストリーム - C# によるプログラミング入門 | ++C++; // 未確認飛行 C