やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

C#8.0非同期using

 DisposeAsyncメソッドがあればawait using(){}時に実行する。

成果物

情報源

DisposeAsyncメソッド

  • await using(){}時に自動で呼び出される
  • 戻り値はawaitできるなら何でもいい
  • インスタンスメソッドのみ可

コード

0

using System;
using System.Threading.Tasks;

namespace AsyncUsing
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await using(var x = new A()) {
                Console.WriteLine("Hello Async Using !!");
            }
        }
        struct A
        {
            // Enumerable必須
            public A GetAsyncEnumerator() => this;
         
            // Enumerator必須
            public int Current => 0;
            public ValueTask<bool> MoveNextAsync()
            {
                Console.WriteLine("MoveNextAsync");
                return new ValueTask<bool>(false);
            }
         
            // 未実装なら呼ばれない
            public ValueTask DisposeAsync()
            {
                Console.WriteLine("DisposeAsync");
                return default;
            }
        }

    }
}
$ dotnet run
Hello Async Using !!
DisposeAsync

1

using System;
using System.Threading.Tasks;
using System.Reflection;

namespace AsyncUsing
{
    class Code1
    {
        public async Task Run()
        {
            await using(var x = new A()) {
                Console.WriteLine($"{this.GetType().Name}");
            }
        }
        class A
        {
            public ValueTask DisposeAsync()
            {
                Console.WriteLine($"{MethodBase.GetCurrentMethod().Name}");
                return default;
            }
        }
    }
}

2

using System;
using System.Threading.Tasks;
using System.Reflection;

namespace AsyncUsing
{
    class Code2
    {
        public async Task Run()
        {
            await using(var x = new A()) {
                Console.WriteLine($"{this.GetType().Name}");
            }
        }
        class A
        {
            public MyAwaitable DisposeAsync()
            {
                Console.WriteLine($"{MethodBase.GetCurrentMethod().Name}");
                return default;
            }
        }
        struct MyAwaitable { public ValueTaskAwaiter GetAwaiter() => default; }
    }
}
  • ValueTaskAwaiter
    • この ValueTask の継続アクションをスケジュール設定します。

所感

 以前から終了処理を表現するものとしてusing(){}記法があった。いちいちDispose()を呼び出さなくとも、ブロック終了時に自動で呼出してくれる。

 今回のawait using(){}は、それの非同期版。

 ValueTaskAwaiterとかはよくわからん。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux