テキスト篇: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); //【変更】
}
}
}