【C#】Taskのキャンセル

C# 標準の Task のキャンセルの方法です。どちらも同じ方法でキャンセルできます。

標準で CancellationTokenSource から得られる CancellationToken を Task.Run の第2 引数に渡すことでキャンセルをハンドルできるようになります。

Taskのキャンセル

static CancellationTokenSource _cs = new();

private static void Main(string[] args)
{
    Foo(_cs.Token);

    while (true)
    {
        Console.Write(">");
        string input = Console.ReadLine();
        if (string.Compare(input.Trim(), "cancel", true) == 0)
        {
            _cs.Cancel();
        }
    }
}

private static async void Foo(CancellationToken ct)
{
    await Task.Run(() =>
    {
        try
        {
            for (int i = 0; i < 100; i++)
            {
                if (ct.IsCancellationRequested)
                {
                    // 検出されたかどうか?
                    Console.WriteLine("キャンセルを検出しました。");
                }

                // キャンセルされてたら OperationCanceledException を投げる
                ct.ThrowIfCancellationRequested();

                Trace.WriteLine($"{DateTime.Now:HH:mm:ss} [{i}]");

                Task.Delay(1000).Wait();
            }
        }
        catch (OperationCanceledException ex)
        {
            Console.WriteLine(ex);
        }
    }
    , ct);
}

上位側で Cancel() を呼び出しても自動で停止したり、例外が勝手に発生したりはしません。

CancellationToken の IsCancellationRequested を参照することで Task 内でキャンセルを検出することが可能です。検出したいタイミングでプロパティを都度確認します。

キャンセルされたのを検出したら例外を投げる場合 ThrowIfCancellationRequested メソッドを使用すると OperationCanceledException が発生します。

Unityの場合

Unity の場合は、Task.Run(... を UniTask.Run(... に変更する + 戻り値がある場合 Task から UniTask に変更することで対応できます。扱い方は完全に同じです。

以上