async

asyncは、一般のメソッド以外に、匿名メソッドやラムダ式に付ける場合もある。

async - C# リファレンス | Microsoft Docs
非同期メソッドの構文(2/3) - @IT

awaitを扱った時の最後のコードを見てみる。

// 名前空間の登録
using System;   // 共通データ型と基本クラス(System名前空間)
using System.Threading; // マルチスレッド(System.Threading名前空間)
using System.Threading.Tasks;   // タスク(System.Threading.Tasks名前空間)

// MainClassの定義
class MainClass
{

    // Mainの定義
    static void Main()
    {

        // 実行前
        Console.WriteLine("Main Begin");    // "Main Begin"と出力.

        // SimpleMethodを実行.
        SimpleMethod(); // SimpleMethodを呼ぶ.

        // SimpleMethodを抜けた後.(awaitで抜けた直後にここは実行される.)
        Console.WriteLine("SimpleMethod After");    // "SimpleMethod After"と出力.

        // 10秒待つ.
        Thread.Sleep(10000); // 10000ミリ秒休止.

        // 実行後
        Console.WriteLine("Main End");    // "Main End"と出力.

    }

    // SimpleMethodの定義
    static async void SimpleMethod()    // awaitのあるメソッドにはasyncを付けないといけない.
    {

        // 実行前
        Console.WriteLine("SimpleMethod Begin");    // "SimpleMethod Begin"と出力.

        // Task.Runで指定のActionを実行.
        await Task.Run(() =>    // awaitでこの処理を待つ.
        {

            // LongProcMethod実行前
            Console.WriteLine("LongProcMethod Before");    // "LongProcMethod Before"と出力.

            // LongProcMethodを実行.
            LongProcMethod();   // LongProcMethodを呼ぶ.

            // LongProcMethod実行前
            Console.WriteLine("LongProcMethod After");    // "LongProcMethod After"と出力.

        });

        // 実行後(上のawaitの付いたタスクが終わるまで実行されない.)
        Console.WriteLine("SimpleMethod End");    // "SimpleMethod End"と出力.

    }

    // LongProcMethodの定義
    static void LongProcMethod()
    {

        // 実行前
        Console.WriteLine("LongProcMethod Begin");    // "LongProcMethod Begin"と出力.

        // 5秒休止で疑似的に長くかかる処理にする.
        Thread.Sleep(5000); // 5000ミリ秒休止.

        // 実行後
        Console.WriteLine("LongProcMethod End");    // "LongProcMethod End"と出力.

    }

}

実行すると、

最初はこう。
最初はこう。

最初はこう。

次はこう
次はこう

次はこう。

最後はこう
最後はこう

最後はこう。
LongProcMethodのThread.Sleepをawait Task.Delayにしてみる。
そうすると、LongProcMethodもasyncにしないといけない。

// 名前空間の登録
using System;   // 共通データ型と基本クラス(System名前空間)
using System.Threading; // マルチスレッド(System.Threading名前空間)
using System.Threading.Tasks;   // タスク(System.Threading.Tasks名前空間)

// MainClassの定義
class MainClass
{

    // Mainの定義
    static void Main()
    {

        // 実行前
        Console.WriteLine("Main Begin");    // "Main Begin"と出力.

        // SimpleMethodを実行.
        SimpleMethod(); // SimpleMethodを呼ぶ.

        // SimpleMethodを抜けた後.(awaitで抜けた直後にここは実行される.)
        Console.WriteLine("SimpleMethod After");    // "SimpleMethod After"と出力.

        // 10秒待つ.
        Thread.Sleep(10000); // 10000ミリ秒休止.

        // 実行後
        Console.WriteLine("Main End");    // "Main End"と出力.

    }

    // SimpleMethodの定義
    static async void SimpleMethod()    // awaitのあるメソッドにはasyncを付けないといけない.
    {

        // 実行前
        Console.WriteLine("SimpleMethod Begin");    // "SimpleMethod Begin"と出力.

        // Task.Runで指定のActionを実行.
        await Task.Run(() =>    // awaitでこの処理を待つ.
        {

            // LongProcMethod実行前
            Console.WriteLine("LongProcMethod Before");    // "LongProcMethod Before"と出力.

            // LongProcMethodを実行.
            LongProcMethod();   // LongProcMethodを呼ぶ.

            // LongProcMethod実行前
            Console.WriteLine("LongProcMethod After");    // "LongProcMethod After"と出力.

        });

        // 実行後(上のawaitの付いたタスクが終わるまで実行されない.)
        Console.WriteLine("SimpleMethod End");    // "SimpleMethod End"と出力.

    }

    // LongProcMethodの定義
    static async void LongProcMethod()  // asyncにする.
    {

        // 実行前
        Console.WriteLine("LongProcMethod Begin");    // "LongProcMethod Begin"と出力.

        // Task.Delayで5秒待つ.
        await Task.Delay(5000); // 5000ミリ秒待つ.

        // 実行後
        Console.WriteLine("LongProcMethod End");    // "LongProcMethod End"と出力.

    }

}

とすると、

最初こうなって
最初こうなって

最初こうなって、

次こうなって
次こうなって

次こうなって、

最後こうなる
最後こうなる

最後こうなる。
await Task.DelayだとLongProcMethodをすぐ抜けちゃって、"LongProcMethod After"に行ってしまい、Taskがすぐ終わって、"SimpleMethod End"まで行ってしまう。
となると、LongProcMethod自体もawaitしないといけない。
となると、ラムダ式をasyncにしないといけない。

で、こうなるわけだけど、VisualStudio2015だと、awaitする関数がvoidだとasync Taskにしないといけない。async voidにはできない。
たぶん、2013までは書けた気がするが。

C#の非同期メソッドの戻り値のvoidとかTaskがよくわからなかったので動かしてみた - Qiita

ここでも、それ言ってる。
(VS2012, VS2013準備するのも大変なので、それの検証は今回は割愛。)

で、こうすると、

こうなって
こうなって

こうなって、

こうなって
こうなって

こうなって、

こうなる
こうなる

こうなる。
"SimpleMethod After"以外の"~ After"や"~ End"は、長い処理が終わってから通っている。

Sample/cs/async/async/src/async at master · bg1bgst333/Sample · GitHub