講義メモ

テキスト篇:p.310「イベント」から
ゲーム開発演習:塗りつぶし、文字の描画、タイトル画面と画面遷移 など

p.310 イベント

・コンソールアプリケーションにおけるConsole.ReadLineのように、起動したプログラムが動的に情報を得る手段がある
・しかし、これは単なる入力待ちであり、プログラム側の制御はできない(OSに制御を渡してしまう)
・そこで、予め「これが起きたらこれをする」という定義ができ、動的に呼び出される仕掛けとして用意されたのがイベント
・キー入力、マウスの操作、通信の受信などの「何かが起きた」ことをイベントの発生といい、イベントに対して処理を実行するものを
 イベントハンドラという。
 ※ イベントの概念や用語は言語により異なり、Java言語ではイベントリスナという(一部のC#系文書でもこの表現で呼ぶことがある)
・C#では主にフォームアプリケーションでイベントを扱うが、コンソールアプリケーションでもデリゲートを用いることでイベント処理の
 実装が可能
・例えば、Enterキー以外のキー入力を即時に受け取る仕掛けを実装できる

p.312 イベントのプログラミング

・コンソールアプリケーションでデリゲートを用いてイベント処理を実装するには、内部的にイベントを発生させ、これを受けて処理する
 メソッドを記述する
・実装としては、まず、イベントの発生を担うクラスを定義し、その中にイベントフィールドと呼ばれるデリゲートと、イベントを発生させる
 メソッドを記述する。
・イベントフィールドは、デリゲートを型とする特殊なpublicメンバで、メンバ名がイベント名になる
・書式: public event デリゲート名 イベント名;
※ つまり、イベントの発生を担うクラスにはメソッドやデータメンバに加えてイベントを記述する
・イベントを発生させるメソッドは、通常「On」+「イベント名」をメソッド名として定義し、その中でイベント名をメソッドと同様に
 呼び出すことでイベントを発生させる。
・書式: public void/戻り値型 Onイベント名() {…} 
・このメソッドの中でイベント名を用いてイベントを発生させるが、イベントフィールドの準備が出来ていない(イベントがnullである状態)の
 時に呼び出してしまわないように留意する
・書式: if (イベント名 != null) { イベント名(); }
・このクラスを用いて、イベント処理を行いたい側のMainメソッドの記述法
 ① イベントの発生を担うクラスのインスタンスを生成
 ② イベントの発生により動作させたいメソッドを準備(他のクラスのメソッドでも良い)
 ③ ①の参照変数.イベントに対して、②をマルチキャストデリゲーション指定することで登録
 ④ ①の参照変数.Onイベント()メソッドを呼び出すことでイベントを発生させる

p.313 event01.cs

//p.313 event01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値なし、引数なし)
class MyEventClass { //イベントの発生を担うクラス
    public event MyDelegate eventname; //イベントフィールドをイベント名evantnameで定義
    public void OnEventname() { //evantnameイベントを発生させるメソッド
        if (eventname != null) //イベントフィールドが無(準備中)でなければ
            eventname(); //イベントを発生させる
    }
}
class MyClass { //イベントの発生により実行したいメソッド①を持つクラス
    public void show() { //イベントの発生により実行したいメソッド①
        Console.WriteLine("show");
    }
}
class MyClass2 { //イベントの発生により実行したいメソッド②を持つクラス
    public void show2() { //イベントの発生により実行したいメソッド②
        Console.WriteLine("show2!!");
    }
}
class event01 {
    public static void Main() {
        MyClass mc = new MyClass(); //イベントの発生により実行したいメソッド①を持つクラスのインスタンスを生成
        MyClass2 mc2 = new MyClass2(); //イベントの発生により実行したいメソッド②を持つクラスのインスタンスを生成
        MyEventClass myevent = new MyEventClass(); //イベントの発生を担うクラスのインスタンスを生成
        myevent.eventname += new MyDelegate(mc.show); //イベントに対して①をマルチキャストデリゲーション指定することで登録
        myevent.eventname += new MyDelegate(mc2.show2); //イベントに対して②をマルチキャストデリゲーション指定することで登録
        myevent.OnEventname(); //イベントを発生させる
    }
}

アレンジ演習:p.313 event01.cs

・マルチキャストデリゲーションをラムダ式で記述しよう

作成例

//アレンジ演習:p.313 event01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値なし、引数なし)
class MyEventClass { //イベントの発生を担うクラス
    public event MyDelegate eventname; //イベントフィールドをイベント名evantnameで定義
    public void OnEventname() { //evantnameイベントを発生させるメソッド
        if (eventname != null) //イベントフィールドが無(準備中)でなければ
            eventname(); //イベントを発生させる
    }
}
class MyClass { //イベントの発生により実行したいメソッド①を持つクラス
    public void show() { //イベントの発生により実行したいメソッド①
        Console.WriteLine("show");
    }
}
class MyClass2 { //イベントの発生により実行したいメソッド②を持つクラス
    public void show2() { //イベントの発生により実行したいメソッド②
        Console.WriteLine("show2!!");
    }
}
class event01 {
    public static void Main() {
        MyClass mc = new MyClass(); //イベントの発生により実行したいメソッド①を持つクラスのインスタンスを生成
        MyClass2 mc2 = new MyClass2(); //イベントの発生により実行したいメソッド②を持つクラスのインスタンスを生成
        MyEventClass myevent = new MyEventClass(); //イベントの発生を担うクラスのインスタンスを生成
        myevent.eventname += () => mc.show(); //イベントに対して①をマルチキャストデリゲーション指定することで登録
        myevent.eventname += () => mc2.show2(); //イベントに対して②をマルチキャストデリゲーション指定することで登録
        myevent.OnEventname(); //イベントを発生させる
    }
}

アレンジ演習:p.313 event01.cs

・マルチキャストデリゲーションを匿名メソッドで記述しよう
・すると、イベントの発生により実行したいメソッドを持つ2クラスが不要になる

作成例

//アレンジ演習:p.313 event01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値なし、引数なし)
class MyEventClass { //イベントの発生を担うクラス
    public event MyDelegate eventname; //イベントフィールドをイベント名evantnameで定義
    public void OnEventname() { //evantnameイベントを発生させるメソッド
        if (eventname != null) //イベントフィールドが無(準備中)でなければ
            eventname(); //イベントを発生させる
    }
}
class event01 {
    public static void Main() {
        MyEventClass myevent = new MyEventClass(); //イベントの発生を担うクラスのインスタンスを生成
        myevent.eventname += () => {Console.WriteLine("show");}; //イベントに対して匿名メソッドをマルチキャストデリゲーション指定する
        myevent.eventname += () => {Console.WriteLine("show2");}; //イベントに対して匿名メソッドをマルチキャストデリゲーション指定する
        myevent.OnEventname(); //イベントを発生させる
    }
}

p.316 Char構造体と静的メソッド

・System.Char構造体はC#が提供する文字処理用の構造体で、便利な静的メソッドを提供する
※ charをプロパティに前置すると.NET型のSyster.Charに書き換えられ、これを担う構造体とみなされる
・bool Char.IsDigit(char):1文字を受け取って10進数字(0~9)であるかどうかを返す
・double Char.GetNumericValue(char):1文字を受け取って実数変換して返す(変換不可時は-1.0を返す)
※ double.Parse("" + char) や Convert.ToDouble("" + char) と類似だが、これらは変換不可時は異常終了

p.317 ConsoleKeyInfo構造体とプロパティ

・System.ConsoleKeyInfo構造体は、押されたキーの情報を返すためのデータ構造と、便利なプロパティを持つ構造体
・Consoleクラスが提供するReadKeyメソッドの戻り値型がConsoleKeyInfo構造体であり、このメソッドを実行すると、押されたキーの情報をこの構造体に格納してくれる
・この時、引数としてキー情報のコンソールのへの非表示をtrueで指示できる
・書式: ConsoleKeyInfo 変数名 = Console.ReadKey(true);
・bool Console.KeyAvailableプロパティ(p.293)で、キー入力があったかどうかが得られるので、これがtrueであれば、ReadKeyメソッドを用いると良い
・そして、ConsoleKeyInfo構造体のchar KeyCharプロパティで、押されていた文字が得られる

p.315 event02.cs

//p.315 event02.cs
using System;
delegate void Handler(char ch); //デリゲートの宣言(戻り値なし、引数有り)
class EventClass { //イベントの発生を担うクラス
    public event Handler KeyHit; //イベントフィールドをイベント名KeyHitで定義
    public void OnKeyHit(char ch) { //KeyHitイベントを発生させるメソッド
        if (KeyHit != null) //イベントフィールドが無(準備中)でなければ
            KeyHit(ch); //イベントを発生させる
    }
}
class Show { //イベントの発生により実行したいメソッドを持つクラス
    int sum = 0; //合計値
    public void keyshow(char ch) { //イベントの発生により実行したいメソッド
        if (Char.IsDigit(ch)) { //文字が10進数字(0~9のキーが押されていたら)?
            int a = (int)Char.GetNumericValue(ch); //実数化&整数化する
            sum += a; //合計に足し込む
            Console.WriteLine("+ {0}", a); //押されたキーの値を表示
            Console.WriteLine("= {0}", sum); //合計値を表示
        } else if (ch == 'c') { //文字がc(cキーが押されていたら)?
            sum = 0; //合計値クリア
            Console.WriteLine("合計がクリアされました");
        } else { //10進数字,'c'以外であれば
            return; //何もしない
        }
    }
}
class event02 {
    public static void Main() {
        ConsoleKeyInfo cki; //キー情報を得るためのデータ構造等を持つ構造体
        EventClass ec = new EventClass(); //イベントの発生を担うクラスのインスタンスを生成
        Show s = new Show(); //イベントの発生により実行したいメソッドを持つクラスのインスタンスを生成
        ec.KeyHit += new Handler(s.keyshow); //イベントにマルチキャストデリゲーション指定することで登録
        while (true) { //無限ループ
            if (Console.KeyAvailable) { //何かキーが押されている?
                cki = Console.ReadKey(true); //そのキーを得る
                if (cki.KeyChar == 'x') { //xキーであれば
                    break; //繰り返し終了
                } else { //xキー以外?
                    ec.OnKeyHit(cki.KeyChar); //イベントを発生させる
                }
            }
        }
    }
}

アレンジ演習:p.315 event02.cs

・p.319下から2行目のとおり、ラムダ式で書き換えよう

作成例

//アレンジ演習:p.315 event02.cs
using System;
delegate void Handler(char ch); //デリゲートの宣言(戻り値なし、引数有り)
class EventClass { //イベントの発生を担うクラス
    public event Handler KeyHit; //イベントフィールドをイベント名KeyHitで定義
    public void OnKeyHit(char ch) { //KeyHitイベントを発生させるメソッド
        if (KeyHit != null) //イベントフィールドが無(準備中)でなければ
            KeyHit(ch); //イベントを発生させる
    }
}
class Show { //イベントの発生により実行したいメソッドを持つクラス
    int sum = 0; //合計値
    public void keyshow(char ch) { //イベントの発生により実行したいメソッド
        if (Char.IsDigit(ch)) { //文字が10進数字(0~9のキーが押されていたら)?
            int a = (int)Char.GetNumericValue(ch); //実数化&整数化する
            sum += a; //合計に足し込む
            Console.WriteLine("+ {0}", a); //押されたキーの値を表示
            Console.WriteLine("= {0}", sum); //合計値を表示
        } else if (ch == 'c') { //文字がc(cキーが押されていたら)?
            sum = 0; //合計値クリア
            Console.WriteLine("合計がクリアされました");
        } else { //10進数字,'c'以外であれば
            return; //何もしない
        }
    }
}
class event02 {
    public static void Main() {
        ConsoleKeyInfo cki; //キー情報を得るためのデータ構造等を持つ構造体
        EventClass ec = new EventClass(); //イベントの発生を担うクラスのインスタンスを生成
        Show s = new Show(); //イベントの発生により実行したいメソッドを持つクラスのインスタンスを生成
        ec.KeyHit += (c) => s.keyshow(c); //【変更】イベントにマルチキャストデリゲーション指定することで登録
        while (true) { //無限ループ
            if (Console.KeyAvailable) { //何かキーが押されている?
                cki = Console.ReadKey(true); //そのキーを得る
                if (cki.KeyChar == 'x') { //xキーであれば
                    break; //繰り返し終了
                } else { //xキー以外?
                    ec.OnKeyHit(cki.KeyChar); //イベントを発生させる
                }
            }
        }
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です