【C#】Delegate / Event ~ 非同期デリゲート・バックグラウンド処理を行う ~

■ はじめに

https://dk521123.hatenablog.com/entry/2010/12/12/164101
https://dk521123.hatenablog.com/entry/2010/12/25/221009
https://dk521123.hatenablog.com/entry/2010/10/22/101350

の続き。

 ■ 基本的な流れ

1)非同期で呼び出すメソッドと同じシグネチャを持つデリゲートを用意
2)用意したデリゲートから BeginInvoke メソッドにより、非同期実行を開始
3)BeginInvoke 指定の際、非同期処理が終了したときのメソッド(例:EndInvoke())を指定

 => 以下の「■ サンプル」の「例1」のコメントと対比してみるといいかも

 ■ サンプル

例1:処理を別スレッドで実行
例2:処理を別スレッドに処理状況をみて実行

 例1:処理を別スレッドで実行

キーワード

 * IAsyncResult
 * BeginInvoke/EndInvoke()

Form1.cs

using System;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    // 【1】 非同期で呼び出すメソッド(DelegatingMethod())と同じシグネチャを持つデリゲートを用意
    // 非同期実行するためのデリゲート
    private delegate string SampleDelegate(int sleep, string format);

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      // 実行するデリゲートを作成
      SampleDelegate sampleDelegate =
          new SampleDelegate(this.DelegatingMethod);

      // 【2】 用意したデリゲートから BeginInvoke メソッドにより、非同期実行を開始
      // 非同期で呼び出す
      IAsyncResult asyncResult =
          sampleDelegate.BeginInvoke(5000, "yyyy/MM/dd", null, null);
      this.label1.Text = "Called BeginInvoke()";

      // 【3】 BeginInvoke 指定の際、非同期処理が終了したときのメソッド(例:EndInvoke())を指定
      // 処理結果取得
      string resultFromDelegatingMethod = sampleDelegate.EndInvoke(asyncResult);
      this.label2.Text = "Called EndInvoke() : Today is " + resultFromDelegatingMethod;
    }

    // 非同期させたい(重たい)処理
    private string DelegatingMethod(int sleep, string format)
    {
      System.Threading.Thread.Sleep(sleep);
      return DateTime.Now.ToString(format);
    }
  }
}

出力結果

【ボタン押下直後】
Called BeginInvoke()
label2

【ボタン押下5秒後】
Called BeginInvoke()
Called EndInvoke() : Today is 2013/05/27

 例2:処理を別スレッドに処理状況をみて実行

キーワード

 * IAsyncResult
 * AsyncWaitHandle.WaitOne()
 * IAsyncResult.IsCompleted

Form1.cs

using System;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    // 非同期実行するためのデリゲート
    private delegate string SampleDelegate(int sleep, string format);


    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      // 実行するデリゲートを作成
      SampleDelegate sampleDelegate =
          new SampleDelegate(this.DelegatingMethod);

      // 非同期で呼び出す。
      IAsyncResult asyncResult =
          sampleDelegate.BeginInvoke(5000, "yyyy/MM/dd", null, null);
      this.label1.Text = "Called BeginInvoke()";

      // 2秒だけ処理を中断して別スレッドの計算を待つ
      asyncResult.AsyncWaitHandle.WaitOne(2000);
      if (asyncResult.IsCompleted)
      {
        // ここは実行されない(処理に5秒かかるが上で2秒しかまってないから実行されず)
        this.label2.Text = "Still Running?";
      }
      else
      {
        this.label3.Text = "Yes, Still Running...";
      }

      this.label4.Text = "Before calling AsyncWaitHandle.WaitOne...";
      // 別スレッドの処理が終わるまで待つ
      asyncResult.AsyncWaitHandle.WaitOne();
      this.label4.Text = "Called AsyncWaitHandle.WaitOne...";
      if (asyncResult.IsCompleted)
      {
        // 処理結果取得
        string resultFromDelegatingMethod = sampleDelegate.EndInvoke(asyncResult);
        this.label5.Text = "Today is " + resultFromDelegatingMethod;
      }
    }

    // 非同期させたい(重たい)処理
    private string DelegatingMethod(int sleep, string format)
    {
      System.Threading.Thread.Sleep(sleep);
      return DateTime.Now.ToString(format);
    }
  }
}

出力結果

【ボタン押下直後】
Called BeginInvoke()
label2
label3
label4
label5

【ボタン押下2秒後】
Called BeginInvoke()
label2
label3
Before calling AsyncWaitHandle.WaitOne...
label5

【ボタン押下5秒後】
Called BeginInvoke()
label2
Yes, Still Running
Called AsyncWaitHandle.WaitOne...
Today is 2013/05/27

 参考文献

http://d.hatena.ne.jp/gsf_zero1/20090312/p1
http://d.hatena.ne.jp/teramonagi/20110820/1313838406
http://acha-ya.cocolog-nifty.com/blog/2010/09/post-fe36.html
http://n2-csharp.blogspot.jp/2009/09/blog-post_26.html

 関連記事

Delegate / Event ~ 入門編 / Delegate
https://dk521123.hatenablog.com/entry/2010/12/12/164101
Delegate / Event ~ 入門編 / Event ~
https://dk521123.hatenablog.com/entry/2010/12/25/221009