CUIとGUI

 GUIの場合は、「ボタンを押したらどうするか」を決めて、そのまま全処理を終了する。そしてボタンが押されるのを待ち、ボタンが押されると新たな処理が起動する。

 CUIの場合というわけではないが、たとえばscanfとすると、処理が止まる。入力されるのを待って、入力を受け取り次の処理に進む。

 見た感じどっちが分かりやすいかといえば後者だ。GUIでもダイアログを開く場合には処理が止まる。

 1番と2番、どちらを選ぶかを決めるコードを書いてみる。

//止まる版
void Select()
{
  int a = Read();
  switch(a)
    case 1:
      Hoge1();
    case 2:
      Hoge2();
}

//止まらない版
void Select()
{
  button1.Clicked += Hoge1;
  button2.Clicked += Hoge2;
}

 止まる版の一番の問題は、呼び出されたHogeの中で再びSelectが呼び出せないことだ。HogeがSelectを呼び出し、またHogeがSelectを呼び出し・・・と続けていくと、無限ループになりいずれスタックが溢れてしまう(ものすごい時間がかかるだろうけど)。しかしHoge()から呼び出される先でSelect()を呼び出さないという制限を課す確実な方法がない。

 止まらない版の、全処理を終了することでしかこれが実現できない。それか決して呼び出されないMainメソッドまでreturnするか。

 止まる版と止まらない版のinterfaceを共通にしたい。scanfで選択する場合とGUIで選択する場合を同じように使いたい。しかし使われ方が全く違う。普通にやると実行順序が確実に変わってしまう。

 こんな感じかな。

void Select(Action hoge1, Action hoge2)
{
  Thread current = Thread.CurrentThread;
  new Thread( () => NewThread(current, hoge1, hoge2) ).Start();
}

void NewThread(Thread current, Action hoge1, Action hoge2)
{
  //呼び出し元の処理を全部終わらせる
  current.Join();

  int a = Read();
  switch(a)
    case 1:
      hoge1();
    case 2:
      hoge2();
}

 どっちにせよ呼び出し元の処理が先に終わる形に揃える感じで。