非同期ラムダの利用 - await async と併用したラムダ式の利用 - C#

非同期ラムダの利用とコードについて紹介します。

概要

ラムダ式を利用するとデリゲートをシンプルに記述することができます。(参考)
一方でメソッドには従来から利用されてきた同期メソッドに加え、非同期メソッドがC# 5.0から利用できるようになりました。 非同期メソッドのデリゲートをラムダ式で表現することもできます。この記事では、ラムダ式で非同期メソッドのデリゲートを表現する方法を紹介します。

書式

以下の書式を利用します。
async (ラムダ式)

非同期ラムダを利用しない場合

UI

下図のUIを作成します。

コード

非同期ラムダを利用しない場合のコードです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AsyncLambdaExpressions
{
  public partial class FormMain : Form
  {
    int value = 200;

    public FormMain()
    {
      InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
      await AsyncProc();
      textBox1.Text += "value:"+Convert.ToString(value)+"\r\n";
    }

    private async Task AsyncProc()
    {
      await Task.Delay(1000);
      value += 100;
    }
  }
}

解説

button1をクリックすると、await async を利用した非同期処理でAsyncProc()が呼び出されます。
AsyncProcではDelay処理により、処理が1秒間停止しますが、AsybncProc自体が非同期で呼び出されているため、Delay中でもUIはフリーズせずに操作できます。Delay後valueに100を加算し、AsybncProcを抜けます。
メインスレッドは、button1のClickでawait AsynProc()を呼び出した後は、以降の行は実行せず、非同期処理の戻りを待つため、valueに100が加算され、AsyncProc関数の処理を抜けた後で、テキストボックスにvalueの値を表示します。

async, awaitの動作の詳細についてはこちらの記事を参照してください。

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。初期値の200に100を加算した"300"がテキストボックスに表示されます。


[button1]をクリックするごとに、100加算された値がテキストボックスに表示されます。

非同期ラムダを利用する場合

先のプログラムをラムダ式を利用したコードに変更します。

UI

UIは先のプログラムと同じものを利用します。

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AsyncLambdaExpressions
{
  public partial class FormMain : Form
  {
    int value = 200;

    public FormMain()
    {
      InitializeComponent();

      button2.Click += async (sender, e) =>
      {
        await AsyncProc();
        textBox1.Text += "value:" + Convert.ToString(value) + "\r\n";
      };
    }

    private async Task AsyncProc()
    {
      await Task.Delay(1000);
      value += 100;
    }
  }
}

解説

button2のClickイベントをフォームのコンストラクタ中で実装しています。
デリゲートとラムダ式の書き換えでも紹介している、デリゲートをラムダ式で記述する方式でbutton2のclickイベントを実装しています。
ただし、今回はasync, await を用いた非同期関数の実装のため、ラムダ式の先頭に async キーワードを記述します。

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。初期値の200に100を加算した"300"がテキストボックスに表示されます。


[button1]をクリックするごとに、100加算された値がテキストボックスに表示されます。

非同期ラムダを利用する場合 (その2)

上記のコードでは、AsyncProc() メソッドをメソッドで実装していましたが、この処理を非同期ラムダ式を利用してインラインで記述するコードを紹介します。

UI

UIは先のプログラムのUIにボタンを一つ追加します。

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AsyncLambdaExpressions
{
  public partial class FormMain : Form
  {
    int value = 200;

    public FormMain()
    {
      InitializeComponent();

      button3.Click += async (sender, e) =>
      {
        Func<Task> f = async () =>{
          await Task.Delay(1000);
          value += 100;
        };
        await f();

        textBox1.Text += "value:" + Convert.ToString(value) + "\r\n";
      };
    }
  }
}

解説

button3のClickイベントをフォームのコンストラクタ中で実装しています。
デリゲートをラムダ式で記述する方式でbutton2のclickイベントを実装しています。先のコードと同様に非同期メソッドになるため、ラムダ式の先頭に async キーワードを記述します。
また、メソッドの実装部分で、先のプログラムでは AsyncProc() メソッドを非同期で呼び出していましたが、今回はメソッドで記述せずにインラインで記述します。 インラインで非同期メソッドを記述する場合は、Func<Task>' の型の変数を宣言します。宣言した変数への代入はラムダ式を利用します。 ラムダ式の右辺にメソッドで実行するコート度記述します。今回の処理は先のプログラムの処理と同様に value メンバ変数に100を加算する処理をします。
メソッドの呼び出しは先のコードと同様に
await` キーワードを記述して呼び出します。

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button3]をクリックします。初期値の200に100を加算した"300"がテキストボックスに表示されます。


[button1]をクリックするごとに、100加算された値がテキストボックスに表示されます。先に紹介したコードと同じ動作になっていることが確認できます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2016-07-15
iPentec all rights reserverd.