やってみる

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

C#8.0非同期ストリーム(非同期foreach。パターンベース)

 継承不要(ダックタイピング)。

成果物

情報源

コード

1

using System;
using System.Threading.Tasks; // Task

namespace AsyncForeach
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await foreach (var x in new A()) { Console.WriteLine($"{x}"); }
        }
        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;
            }
        }
    }
}

 以下の要素が実装されていればいい。そのために何かを継承する必要はない。継承不要のことをパターンベースと呼んでいるっぽい。別サイトではダックタイピングと言っていた。謎の用語が飛び交う魔界。

  • GetAsyncEnumerator
  • Current
  • MoveNextAsync

 以下が実装されていればasync using(var x = new A()) {}で呼ばれる。ただし実装は必須ではなく任意。なくてもいい。

  • DisposeAsync

実行結果

$ dotnet run
MoveNextAsync
DisposeAsync

 あれ? foreachvar xには何も入っていないのか? falseが返ってくるように見えたのだが……。

2

using System;
using System.Threading.Tasks; // Task
using System.Threading; // CancellationToken

namespace AsyncForeach
{
    class Program
    {
        static async Task Main(string[] args)
        {
            await foreach (var x in new B()) { Console.WriteLine($"{x}"); }
        }
        struct B
        {
            // 可変長引数可
            public B GetAsyncEnumerator(params int[] dummy) => this;
            public int Current => 0;
            // オプション引数可
            public ValueTask<bool> MoveNextAsync(CancellationToken token = default) => default;
        }
    }
}

 同期版の各メソッドと違う点として以下がある。

  • 可変長引数が使える
  • オプション引数が使える

 以下参考。

所感

 どういうときに、どう使えるのか、わからなかった。だってループなのに何も出てないじゃん。

対象環境

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