テキスト篇:p.301「マルチキャストデリゲーション」から
ゲーム開発演習:同心円の描画のフォロー、塗りつぶし、文字の描画、タイトル画面と画面遷移 など
p.301 マルチキャストデリゲーション
・デリゲートの登録に「+=」を用いることで、1つのデリゲートに2つ以上のオブジェクトを登録することが可能 ・これをマルチキャストデリゲーションといい、呼び出しにより、複数のメソッドが順に動作する ・動作順序の保証がないため、戻り値型がvoidであるデリゲートに限る ・例: delegate void デリゲート名(…); //デリゲートの宣言(戻り値無し、引数有り無しどちらもOK)) : デリゲート名 参照変数 = new デリゲート名(メソッド名①); //参照変数で①が呼ばれる 参照変数 += new デリゲート名(メソッド名②); //参照変数で①②が呼ばれる 参照変数 += new デリゲート名(メソッド名③); //参照変数で①②③が呼ばれる ・なお「-=」を用いて、登録済みのデリゲートオブジェクトを取り消し可能 ・例: 参照変数 -= new デリゲート名(メソッド名②); //参照変数で①③が呼ばれる
p.302 delegate05.cs
//p.302 delegate05.cs
using System;
delegate void MyDG(); //デリゲートの宣言(戻り値無し、引数無し)
class MyClass {
public void show1() { //Mainとは異なるクラスにあるインスタンスメソッド①
Console.WriteLine("show1が呼ばれました");
}
public void show2() { //Mainとは異なるクラスにあるインスタンスメソッド②
Console.WriteLine("show2が呼ばれました");
}
public void show3() { //Mainとは異なるクラスにあるインスタンスメソッド③
Console.WriteLine("show3が呼ばれました");
}
}
class delegate05 {
public static void Main() {
MyClass mc = new MyClass(); //インスタンスメソッド①②③のあるクラスのインスタンスを生成
MyDG md = new MyDG(mc.show1); //インスタンスメソッド①のデリゲートを生成しmdとする
Console.WriteLine("1回目のmd()を実行します");
md(); //①が呼ばれる
md += new MyDG(mc.show2); //インスタンスメソッド②のデリゲートを生成しmdに追加登録とする
Console.WriteLine("2回目のmd()を実行します");
md(); //①②が呼ばれる
md += new MyDG(mc.show3); //インスタンスメソッド③のデリゲートを生成しmdに追加登録とする
Console.WriteLine("3回目のmd()を実行します");
md(); //①②③が呼ばれる
md -= new MyDG(mc.show1); //インスタンスメソッド①のデリゲートを生成しmdから解除する
Console.WriteLine("4回目のmd()を実行します");
md(); //②③が呼ばれる
}
}
アレンジ演習:p.302 delegate05.cs
・コンソールに3つのメソッド名を順に表示し「実行しますか(y/n)」で選択できるようにしよう 例: 戦闘相手選択①ドラゴンと戦いますか?(y/n):y 戦闘相手選択②スライムと戦いますか?(y/n):n 戦闘相手選択③大魔導士と戦いますか?(y/n):y ドラゴンを攻撃しました 大魔導士を攻撃しました 戦闘相手選択①ドラゴンと戦いますか?(y/n):
作成例
//アレンジ演習:p.302 delegate05.cs
using System;
delegate void MyDG(); //デリゲートの宣言(戻り値無し、引数無し)
class MyClass {
public void Dragon() { //Mainとは異なるクラスにあるインスタンスメソッド①
Console.WriteLine("ドラゴンを攻撃しました");
}
public void Slime() { //Mainとは異なるクラスにあるインスタンスメソッド②
Console.WriteLine("スライムを攻撃しました");
}
public void Daimado() { //Mainとは異なるクラスにあるインスタンスメソッド③
Console.WriteLine("大魔導士を攻撃しました");
}
}
class delegate05 {
public static void Main() {
MyClass mc = new MyClass(); //インスタンスメソッド①②③のあるクラスのインスタンスを生成
MyDG md; //デリゲートの参照変数を宣言
string ans = "";
do {
md = null; //デリゲートを無しにしておく
Console.Write("戦闘相手選択①ドラゴンと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += new MyDG(mc.Dragon); //インスタンスメソッド①のデリゲートを生成しmdに登録
}
Console.Write("戦闘相手選択②スライムと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += new MyDG(mc.Slime); //インスタンスメソッド②のデリゲートを生成しmdに登録
}
Console.Write("戦闘相手選択③大魔導士と戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += new MyDG(mc.Daimado); //インスタンスメソッド③のデリゲートを生成しmdに登録
}
if (md != null) { //1つでも登録されていたら
md(); //マルチキャストデリゲートを実行
}
} while (md != null);
}
}
p.304 匿名メソッド
・デリゲートに既存のメソッドを登録する代わりに、登録内容をそのまま記述できる
・書式: デリゲート名 参照変数 = delegate(引数リスト){メソッドの内容};
・例:MyDG md = delegate() { Console.WriteLine("show1が呼ばれました"); };
・こうするとメソッド名がなくなるので、匿名メソッドという
・マルチキャストデリゲーションも可能だが「-=」は不可なので注意
p.304 anomethed01.cs
//p.304 anomethed01.cs
using System;
delegate int MyDelegate(string s); //デリゲートの宣言(戻り値有り、引数有り)
class MyClass {
public int Show(string s) { //Mainとは異なるクラスにあるインスタンスメソッド
Console.WriteLine("{0}と入力されました。", s);
return 0;
}
}
class AnoMethed01 {
public static void Main() {
MyClass mc = new MyClass();
Console.Write("文字列入力 --- ");
string x = Console.ReadLine();
//従来型
MyDelegate mdg = new MyDelegate(mc.Show);
mdg(x);
//匿名メソッド
MyDelegate mdg2 = delegate (string i) { //引数有り
Console.WriteLine("{0}と入力されました。", i);
return 0;
};
mdg2(x); //呼び出し方法は同じ
}
}
アレンジ演習:p.304 anomethed01.cs
・従来型の部分をすべて削除しよう
作成例
//p.304 anomethed01.cs
using System;
delegate int MyDelegate(string s); //デリゲートの宣言(戻り値有り、引数有り)
class AnoMethed01 {
public static void Main() {
Console.Write("文字列入力 --- ");
string x = Console.ReadLine();
//匿名メソッド
MyDelegate mdg2 = delegate (string i) { //引数有り
Console.WriteLine("{0}と入力されました。", i);
return 0;
};
mdg2(x); //呼び出し方法は同じ
}
}
アレンジ演習:p.302 delegate05.cs(その2)
・3つのデリゲート用メソッドをすべて匿名メソッドにしよう
作成例
//アレンジ演習:p.302 delegate05.cs(その2)
using System;
delegate void MyDG(); //デリゲートの宣言(戻り値無し、引数無し)
class delegate05 {
public static void Main() {
MyDG md; //デリゲートの参照変数を宣言
string ans = "";
do {
md = null; //デリゲートを無しにしておく
Console.Write("戦闘相手選択①ドラゴンと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += delegate(){Console.WriteLine("ドラゴンを攻撃しました");}; //匿名メソッドをmdに登録
}
Console.Write("戦闘相手選択②スライムと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += delegate(){Console.WriteLine("スライムを攻撃しました");}; //匿名メソッドをmdに登録
}
Console.Write("戦闘相手選択③大魔導士と戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += delegate(){Console.WriteLine("大魔導士を攻撃しました");}; //匿名メソッドをmdに登録
}
if (md != null) { //1つでも登録されていたら
md(); //マルチキャストデリゲートを実行
}
} while (md != null);
}
}
p.306 ラムダ式
・元は関数の簡易書式で、多くの仕掛けやプログラム言語に採用されている ・ただし、活用場面によって文法が異なることがあり注意 ・C#では主に、匿名メソッドの簡易記述に活用する ・書式: (引数リスト) => 式; //引数リストでは型の記述は不要 ・例: (x) => Show(x); //引数xを渡してShowメソッドを呼ぶ ・なお、引数がないメソッドの場合「()」のみ記述する ・例: () => Show(); //引数のないShowメソッドを呼ぶ ・これをデリゲートのメソッド登録に用いると良い ・例:MyDelegate mdg = new MyDelegate(mc.Show); ⇒ MyDelegate mdg = () => mc.Show();
p.307 lambda01.cs
//p.307 lambda01.cs
using System;
delegate void MyDelegate(); //デリゲートの宣言(戻り値無し、引数無し)
class lambda01 {
public static void show() {
Console.WriteLine("呼ばれました");
}
public static void Main() {
// 直接showメソッドを呼び出す
show();
// デリゲートの作成
MyDelegate md = () => show(); //元は「MyDelegate md = new MyDelegate(show);」
//デリゲートを通してshowメソッドを実行
md();
}
}
p.308(匿名メソッドとラムダ式)
・ラムダ式でデリゲートの匿名メソッドを記述できる
・例:MyDelegate md = delegate () { Console.WriteLine("入力されました");};
⇒ MyDelegate md = () => { Console.WriteLine("入力されました");};
・例:MyDelegate md = delegate (i) { Console.WriteLine("{0}と入力されました", i);};
⇒ MyDelegate md = (i) => { Console.WriteLine("{0}と入力されました", i);};
・引数の型はデリゲートの定義を用いて判断される
p.307 lambda02.cs
//p.307 lambda02.cs
using System;
delegate int MyDelegate(int x, int y);
class lambda02
{
public static void Main()
{
MyDelegate md = (x, y) => { return x + y; }; //匿名メソッドをラムダ式に
Console.WriteLine("2 + 3 = {0}", md(2, 3));
}
}
p.308(匿名メソッドとマルチキャストとラムダ式)
・マルチキャストにおいても匿名メソッドをラムダ式で記述して利用できる
・なお「+=」を用いる代わりに、同じデリゲート型の参照変数を複数定義して「参照変数 = 参照変数 + 参照変数」とすることで
マルチキャストを表現できる
⇒ lambda03.csの016行目
・また、ラムダ式の左辺の引数が1個の場合、カッコを省略できる
例:MyDelegate md = (i) => { Console.WriteLine("{0}と入力されました", i);};
⇒ MyDelegate md = i => { Console.WriteLine("{0}と入力されました", i);};
p.309 lambda03.cs
//p.309 lambda03.cs
using System;
delegate void MyDelegate(int x);
class lambda03
{
public static void Main()
{
MyDelegate md1 = x => {Console.WriteLine("{0}の2乗は{1}", x, x * x);}; //ラムダ式で記述①
MyDelegate md2 = x => {Console.WriteLine("{0}の2倍は{1}", x, x * 2);}; //ラムダ式で記述②
MyDelegate md = md1 + md2; //マルチキャストデリゲーションにする
md(10); //①②を呼び出す
}
}
アレンジ演習:p.309 lambda03.cs
・デリゲートの参照変数を3つ用いているのを、1つにしよう
作成例
//アレンジ演習:p.309 lambda03.cs
using System;
delegate void MyDelegate(int x);
class lambda03
{
public static void Main()
{
MyDelegate md = x => {Console.WriteLine("{0}の2乗は{1}", x, x * x);}; //ラムダ式で記述①し登録
md += x => {Console.WriteLine("{0}の2倍は{1}", x, x * 2);}; //ラムダ式で記述②し追加登録
md(10); //①②を呼び出す
}
}
アレンジ演習:p.302 delegate05.cs(その3)
・3つの匿名メソッドをすべてラムダ式にしよう
作成例
//アレンジ演習:p.302 delegate05.cs(その3)
using System;
delegate void MyDG(); //デリゲートの宣言(戻り値無し、引数無し)
class delegate05 {
public static void Main() {
MyDG md; //デリゲートの参照変数を宣言
string ans = "";
do {
md = null; //デリゲートを無しにしておく
Console.Write("戦闘相手選択①ドラゴンと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += () => Console.WriteLine("ドラゴンを攻撃しました"); //ラムダ式でmdに登録
}
Console.Write("戦闘相手選択②スライムと戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += () => Console.WriteLine("スライムを攻撃しました"); //ラムダ式でmdに登録
}
Console.Write("戦闘相手選択③大魔導士と戦いますか?(y/n):"); ans = Console.ReadLine();
if (ans == "y") {
md += () => Console.WriteLine("大魔導士を攻撃しました"); //ラムダ式でmdに登録
}
if (md != null) { //1つでも登録されていたら
md(); //マルチキャストデリゲートを実行
}
} while (md != null);
}
}