C#2.0時代のゲームプログラミング(49) 〜 delegateを用いたcontinuation

よほどのC#初心者でも無い限り、delegateの便利さを理解していて無名delegateを活用するコードを多用していることと思う。しかしdelegateでcontinuationが実現できることは知らない人が多い。


まずcontinuationとは何なのか、何故それが必要なのかを簡単に説明しておく。ここで言うcontinuationとはSchemeで言うcontinuation(継続)である。


簡単に言えば関数の実行を一時的に中断しておいて、次回にその関数が呼び出されたときにその続きを実行する機能である。「ああ、C#ならyieldで出来るよね」と思った人、それ正解。


どこでこの機能が必要なのか。例えば次のプログラム。

ウィンドウ内にダイアログを(DirectXやら何やらを用いて)自前で描画したい。ダイアログは「はい」「いいえ」ボタンがあり、そこがクリックされたときにハンドラが呼び出されるコードはすでに書いてある。

「それでファイナルアンサー?」のダイアログを表示して、「はい」が押されれば「ここでやめたら250万円持ち帰れますがいいんですね?」のダイアログを表示する。さらに「はい」が押されれば「ファイナルアンサー?」と表示する。さらに「はい」が押されたら「残念」と表示する。

このようなプログラムは、常識的には、1度目の「はい」が押された状態と2度目の「はい」が押された状態、3度目の「はい」が押された状態etc..に状態番号(か何か)を割り振り、その状態番号に応じてswitch〜caseで処理するコードをどこかに書く必要がある。


switch (state)
{
case 1 :
if (「はい」が押された)
state = 2;
else
state = 0;
break;

}

こういうように状態を明示的にコードに書くとプログラムが非常に複雑になる。これをyieldを使って書きなおすのも悪くはないが、コードがやや複雑になる。無名delegate本体のなかでdelegateを設定するコードを書くことによってcontinuationが実現できることに気付けば以下のように書けるだろう。


YesNoDialog("それでファイナルアンサー?", delegate
{
YesNoDialog("ここでやめたら250万円持ち帰れますがいいんですね?", delegate
{
YesNoDialog("ファイナルアンサー?", delegate
{
残念();
});
});
});