はじめに
この記事はDeep C# vol.2 – record structに続く記事となります。
第3回 Deep C# は await using
を分析します。
内容としては第1回の Deep C# vol.1 – await foreaachのさらなる内奥に入り込むものともなります。
この記事を通して、await using は await foreach に必須の部品であり、非同期プログラミングの正しい実装のために必要だったことを理解していただけたら幸いです。
await using で非同期化される範囲
await using のどの部分が非同期化対象となるのでしょうか。
まずは簡単なサンプルを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
await using(AsyncDisposableSample sample = new ()) { await sample.Foo(); } class AsyncDisposableSample : IAsyncDisposable { public async ValueTask Foo() => await Task.Delay(0); public async ValueTask DisposeAsync() => await Task.Delay(0); } |
一見するとawait using(/*この中身*/)
が非同期化されるように感じますが、実はこの部分に非同期コードを入れることは昔から可能でした。
コンストラクターは await にすることができないので、上記コードnew ()
は同期的です。
インスタンスの生成を非同期化するためには、非同期のファクトリーメソッドを実装する必要があります。
その場合以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
await using(var sample = await AsyncDisposableSample.Create()) { await sample.Foo(); } internal class AsyncDisposableSample : IAsyncDisposable { private AsyncDisposableSample() { } public async ValueTask Foo() => await Task.Delay(0); public async ValueTask DisposeAsync() => await Task.Delay(0); public static async Task Create() { AsyncDisposableSample instance = new AsyncDisposableSample(); // コンストラクターは非同期化不可能 await Task.Delay(0); // ここで非同期的な処理を実行する return instance; } } |
では await using はどこを非同期化するのでしょうか。
await using() {}
この範囲を抜けるときに呼び出される DisposeAsync() の呼び出しが新たな非同期化対象となります。
await using を解体する
古いC#で記述すると、このような処理と等価です。
1 2 3 4 5 6 7 8 9 10 11 12 |
AsyncDisposableSample sample = await AsyncDisposableSample.Create(); try { await sample.Foo(); } finally { if (sample != null) { await ((IAsyncDisposable)sample).DisposeAsync(); } } |
この処理を非常にすっきりと記述できるようになりました。
この仕掛けは await foreach においてすべての範囲を非同期化するために必要なものであることが分かります。
(詳しくは Deep C# vol.1 – await foreaach をご覧ください。)
まとめ
このこと1つを取っても、C#は言語仕様を更新する際に .NET 自体の使用を変更せずに interface の追加とコンパイラによる新たな解釈とコード展開で乗り切っているものが多いことが分かると思います。
実は async / await
や delegate
や yield return
なども同じような形で言語拡張を成し遂げています。
それらもこのDeep C#のシリーズでひも解く予定です。
次回の題材は、近年になってパターンマッチング機能が充実してきた switch式 です。
ご期待ください。