講義メモ

テキスト篇:p.295「デリゲートとは」から
ゲーム開発演習:矩形や円の描画、文字の描画、画面遷移 など

p.295 デリゲートとは

・メソッドへの参照を保持しておいて、これを用いてメソッドを呼び出せる仕掛け
・つまり、デリゲートを通じてのメソッドの呼び出しが可能
・C/C++における「関数へのポインタ」と同じ考え方を洗練したもの
・イベント処理などで必須のテクニック
・宣言書式: delegate メソッドの戻り値型 デリゲート名(メソッドの引数リスト);
・例:bool answer(int x){…}メソッド用のデリゲートmdならば、delegate bool md(int w) とする
・利用にはデリゲートオブジェクトの生成が必要で、この時に呼び出したいメソッドの指定もできる
・生成書式: デリゲート名 参照変数 = new デリゲート名(メソッド名);
・例:bool answer(int x){…}メソッド用のデリゲートmdならば、md mymd = new md(answer);
・デリゲート経由で指定済のメソッドを呼び出すには、参照変数を別名のように利用できる
・例: bool b = mymd(5); // answer(5)が呼ばれ戻り値が返される

p.297 delegate01.cs

//p.297 delegate01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値無し、引数無し))
class delegate01 {
    public static void show() { //静的メソッド(Mainから直接呼び出せるように)
        Console.WriteLine("呼ばれました");
    }
    public static void Main() {
        //直接showメソッドを呼び出す
        show();
        //デリゲートの作成
        MyDelegate md = new MyDelegate(show); //(同一クラスなので)メソッド名のみ指定でOK
        //デリゲートを通してshowメソッドを実行
        md();
    }
}

p.298(別のクラスにあるメソッドをデリゲート経由で呼び出す)

・別のクラスにあるメソッドもデリゲート経由で呼び出すことができる
・インスタンスメソッドであれば、そのクラスのインスタンスを生成して、用いると良い
・生成書式例: デリゲート名 参照変数 = new デリゲート名(インスタンス名.メソッド名);

p.298 delegate02.cs

//p.298 delegate02.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値無し、引数無し))
class MyClass {
    public void show() { //Mainとは異なるクラスにあるメソッド
        Console.WriteLine("呼ばれました");
    }
}
class delegate02 {
    public static void Main() {
        MyClass mc = new MyClass(); //呼び出したいメソッドのあるクラスのインスタンスを生成
        mc.show(); //インスタンス名経由で直接showメソッドを呼び出す
        MyDelegate m = new MyDelegate(mc.show);  //インスタンス名.メソッド名でデリゲートを生成
        m(); //インスタンス名は不要で、メソッドを呼び出せる
    }
}

p.298(別のクラスにある静的メソッドをデリゲート経由で呼び出す)

・別のクラスにある静的メソッドもデリゲート経由で呼び出すことができる
・静的メソッドであれば、そのクラスのインスタンスを生成したくても良い
・生成書式例: デリゲート名 参照変数 = new デリゲート名(クラス名.メソッド名);

p.299 delegate03.cs

//p.299 delegate03.cs
using System;
delegate string MyDelegate(string a, string b); //デリゲートの宣言(戻り値有り、引数有り))
class MyClass {
    public static string show(string s1, string s2) { //Mainとは異なるクラスにある静的メソッド
        return s1 + "は" + s2 + "です";
    }
}
class delegate03 {
    public static void Main() {
        Console.WriteLine(MyClass.show("猫", "ほ乳類")); //クラス名経由で直接showメソッドを呼び出す
        MyDelegate md = new MyDelegate(MyClass.show); //クラス名.メソッド名でデリゲートを生成
        Console.WriteLine(md("C#", "おもしろい")); //クラス名は不要で、メソッドを呼び出せる
    }
}

p.299(デリゲートの動的な変更)

・デリゲートの生成に用いた参照変数を再利用することで、呼び出されるメソッドを動的に変更できる
 ※ ただし、戻り値型と引数リストが同じであること
・これにより、メソッドを呼び出している部分は変更せずに、呼び出されるメソッドを変えてしまうことが可能
・例:
 delegate bool md(int w); //デリゲートの宣言(戻り値有り、引数有り))
 bool myanswer(int x){…}   //静的メソッド①(Mainから直接呼び出せるように)
 bool youranswer(int x){…} //静的メソッド②(Mainから直接呼び出せるように)
 md mymd; //デリゲート用変数を宣言
 mymd = new md(answer); //デリゲートを作成(myanswer用)し、mymdとする
 bool b1 = mymd(5); // myanswer(5)が呼ばれ戻り値が返される
 mymd = new md(youranswer); //デリゲートを作成(youranswer用)し、mymdを上書きする
 bool b2 = mymd(5); // youranswer(5)が呼ばれ戻り値が返される

p.300 delegate04.cs

//p.300 delegate04.cs
using System;
delegate DateTime MyDelegate(DateTime dt, int n); //デリゲートの宣言(戻り値有り、引数有り))
class MyClass1 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス①にあるインスタンスメソッド①
        return d.AddDays(n); //dのn日後の日付時刻オブジェクトを生成して返す
    }
}
class Myclass2 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス②にあるインスタンスメソッド②
        return d.AddHours(n); //dのn時間後の日付時刻オブジェクトを生成して返す
    }
}
class delegate04 {
    public static void Main() {
        MyClass1 mc1 = new MyClass1(); //インスタンスメソッド①のあるクラスのインスタンスを生成
        Myclass2 mc2 = new Myclass2(); //インスタンスメソッド②のあるクラスのインスタンスを生成
        MyDelegate md = new MyDelegate(mc1.Calc); //インスタンスメソッド①のデリゲートを生成しmdとする
        DateTime dt = DateTime.Now; //現在日付時刻の日付時刻オブジェクトを得る
        DateTime mydate; //受け取り用の変数の宣言
        mydate = md(dt, 100); //インスタンスメソッド①に日付時刻オブジェクトを渡して100日後を得る
        Console.WriteLine("今日から100日後は、{0}です", mydate.ToShortDateString());
        md = new MyDelegate(mc2.Calc); //インスタンスメソッド②のデリゲートを生成しmdを上書きする
        mydate = md(dt, 100); //インスタンスメソッド②に日付時刻オブジェクトを渡して100時間後を得る
        Console.WriteLine("今から100時間後は、{0}です",  mydate);
    }
}

アレンジ演習:p.300 delegate04.cs

・「何日後ですか? 何時間後ですか?(1:何日後 2:何時間後 0:終了)」を入力できるようにしよう
・「1:何日後」が選ばれたら「何日後ですか:」を入力できるようにして、結果を表示しよう
・「2:何時間後」が選ばれたら「何時間後ですか:」を入力できるようにして、結果を表示しよう
・「0:終了」が選ばれるまで何度もくりかえそう

作成例

//アレンジ演習:p.300 delegate04.cs
using System;
delegate DateTime MyDelegate(DateTime dt, int n); //デリゲートの宣言(戻り値有り、引数有り))
class MyClass1 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス①にあるインスタンスメソッド①
        return d.AddDays(n); //dのn日後の日付時刻オブジェクトを生成して返す
    }
}
class Myclass2 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス②にあるインスタンスメソッド②
        return d.AddHours(n); //dのn時間後の日付時刻オブジェクトを生成して返す
    }
}
class delegate04 {
    public static void Main() {
        MyClass1 mc1 = new MyClass1(); //インスタンスメソッド①のあるクラスのインスタンスを生成
        Myclass2 mc2 = new Myclass2(); //インスタンスメソッド②のあるクラスのインスタンスを生成
        MyDelegate md; //【変更】デリゲート用変数を宣言
        DateTime dt; //【変更】現在日付時刻用の変数の宣言
        DateTime mydate; //受け取り用の変数の宣言
        string ans = ""; //【追加】入力用 
        do { //【追加】繰り返し開始
            Console.Write("何日後ですか? 何時間後ですか?(1:何日後 2:何時間後 0:終了):");  //【追加】
            ans = Console.ReadLine(); //【追加】
            dt = DateTime.Now; //【移動】現在日付時刻の日付時刻オブジェクトを得る
            if (ans == "1") { //【追加】何日後?
                Console.Write("何日後:"); int n = int.Parse(Console.ReadLine()); //【追加】
                md = new MyDelegate(mc1.Calc); //【変更】インスタンスメソッド①のデリゲートを生成しmdとする
                mydate = md(dt, n); //【変更】インスタンスメソッド①に日付時刻オブジェクトを渡してn日後を得る
                Console.WriteLine("今日から{0}日後は、{1}です", n, mydate.ToShortDateString()); //【変更】
            } else if (ans == "2") { //【追加】何時間後?
                Console.Write("何時間後:"); int n = int.Parse(Console.ReadLine()); //【追加】
                md = new MyDelegate(mc2.Calc); //インスタンスメソッド②のデリゲートを生成しmdとする
                mydate = md(dt, n); //【変更】インスタンスメソッド②に日付時刻オブジェクトを渡してn時間後を得る
                Console.WriteLine("今から{0}時間後は、{1}です", n, mydate); //【変更】
            }
        } while(ans != "0"); //【追加】0:終了が選ばれなければ繰返す
    }
}

参考:別解(できるだけ共通化してみよう)

//アレンジ演習:p.300 delegate04.cs
using System;
delegate DateTime MyDelegate(DateTime dt, int n); //デリゲートの宣言(戻り値有り、引数有り))
class MyClass1 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス①にあるインスタンスメソッド①
        return d.AddDays(n); //dのn日後の日付時刻オブジェクトを生成して返す
    }
}
class Myclass2 {
    public DateTime Calc(DateTime d, int n) { //Mainとは異なるクラス②にあるインスタンスメソッド②
        return d.AddHours(n); //dのn時間後の日付時刻オブジェクトを生成して返す
    }
}
class delegate04 {
    public static void Main() {
        MyClass1 mc1 = new MyClass1(); //インスタンスメソッド①のあるクラスのインスタンスを生成
        Myclass2 mc2 = new Myclass2(); //インスタンスメソッド②のあるクラスのインスタンスを生成
        MyDelegate md = null; //【変更】デリゲート用変数を宣言
        DateTime dt; //【変更】現在日付時刻用の変数の宣言
        DateTime mydate; //受け取り用の変数の宣言
        string ans = ""; //【追加】入力用 
        string[] dh = {"日", "時間" }; //【追加】表示用
        while(true) { //【追加】繰り返し開始
            Console.Write("何日後ですか? 何時間後ですか?(1:何日後 2:何時間後 0:終了):");  //【追加】
            ans = Console.ReadLine(); //【追加】
            if (ans == "0") break; //【追加】0:終了が選ばれたら抜ける
            dt = DateTime.Now; //【移動】現在日付時刻の日付時刻オブジェクトを得る
            int i = int.Parse(ans) - 1; //【追加】添字にする
            Console.Write("何{0}後:", dh[i]); int n = int.Parse(Console.ReadLine()); //【追加】
            if (i == 0) { //【追加】何日後?
                md = new MyDelegate(mc1.Calc); //【変更】インスタンスメソッド①のデリゲートを生成しmdとする
            } else  { //【追加】何時間後?
                md = new MyDelegate(mc2.Calc); //インスタンスメソッド②のデリゲートを生成しmdとする
            }
            mydate = md(dt, n); //【変更】インスタンスメソッド①か②に日付時刻オブジェクトを渡して得る
            Console.WriteLine("今日から{0}{1}後は、{2}です", n, dh[i], mydate); //【変更】
        }
    }
}

コメントを残す

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