C#をつつく22-イベント。そっちから言ってよね。
インドリィちゃん「くまの中さんは何処へ行ったの?」
インドリ「大阪勉強会だよ。ボクもWebで参加したけどすごく楽しかったピヨッ。」
インドリィちゃん「大阪勉強会はもう終わったでしょ!。何時まで浮かれているのよぉ。まったく・・・ まあいいわ。犬のじゃんぬさんは何処へ行ったの?」
インドリ「うーんとねえ。仕事に疲れている様子だったから、息抜きにネタを求めてスイーツ(笑)を観察しに街へ出かけたと思うピヨ。」
インドリィちゃん「それ、ただの勘でしょぉ。もぅ。本当にインドリは頼りにならないわねぇぇ。」
そうなんです。わんくま動物園の個性的な面々は人気者なので、忙しい彼らが何処へ行ったのか全然把握できなかったのです。 これでは動物園は管理出来ません。鶏唐揚さんが危うくお客に食べられそうになったり、画伯がセクハラしたり、 シャノンさんが宇宙の真理を求めて行方不明になったり・・・etc とにかく色々なハプニングが起こりました。 それで困り果てたドリィちゃんは一つのアイデアを思いつきました。
インドリィちゃん「そうだわ。本人に自己申告してもらってそれに対処しよう。」
今度の例の場合のように、何かのオブジェクトを一部始終監視するには向いていない処理は、 イベントを使用します。生き物には自由に生きる権利があるからね。
※イメージとしてはButtonオブジェクトのClickが分かりやすいと思います。
※でもお話しを書かなきゃ面白くないからね♪
そこまで決まれば話しは早いです。さっそくドリィちゃんは報告する内容を実装しました。
みんなも一緒にみてみよう。
public class MoveEventArgs : EventArgs //ここに注目
{
//移動先
private string m_destination;
public string Destination {
get { return m_destination; }
set { m_destination = value; }
}
//移動目的
private string m_purpose;
public string Purpose {
get { return m_purpose; }
set { m_purpose = value; }
}
public MoveEventArgs( destination, string purpose ) {
this.MovingPerson = person;
this.m_destination = destination;
this.m_purpose = purpose;
}
}
ひとまず、移動先と移動目的さえ分かれば何とかなるとドリィちゃんは考えたのです。 勿論このクラスを定義しただけでは何も起こりません。ですから引き続きドリィちゃんはAnimalクラスに変更を加えました。 こっちのコードも見てみよう。
注目するべきところだけ抜粋
public abstract class Animal
{
//イベントの要素を定義
public delegate void MoveEventHandler(object sender, MoveEventArgs e);
public event MoveEventHandler MoveEvent;
//イベントの発生を通知するメソッド
protected virtual void OnMove( MoveEventArgs e ) {
MoveEventHandler temp = MoveEvent;
if ( temp != null ) temp( this, e );
//入力された値を正しいイベントに変換するメソッド
//※元からあるMoveメソッドを修正しました
public virtual void Move( string destination, string purpose )
{
MoveEventArgs e = new MoveEventArgs( person, destination, purpose );
OnMove( e );
}
}
※ここからはドリィちゃんが書いています。口が悪くなるから心して読んでね(インドリより)
ふぅ~。作業が終わったから私が説明するわ。一回しか言わないからちゃんと聞きなさい。
イベントを実装する手順は次の通り。
- 1.イベントで知りたい情報を定義する。
- 2.イベントの要素を定義する。
- 3.イベントの発生を通知するメソッドを定義する。
- 4.入力された値を正しいイベントに変換するメソッドを定義する。
トリ邪魔。部屋の中で飛ぶな。
1の手順ではEventArgsから派生したクラスを定義。 いい、EventArgsよ。他のオブジェクトは駄目。我儘は許さないぃぃ。
(黙って窓を開ける)
2の手順では、eventを宣言することになるわ。
アクセス修飾子 event メソッドの定義 イベントの名前を定義すれば良い。メソッドの定義の部分は難しいけど、今のところは気にしない。 後でインドリが説明するから。じゃあ、次。
だ・か・ら、室内で飛ばないでぇぇ!。羽がキーボードの上に落ちるでしょぉ。もぉ。
3の手順は厄介。コードの行数は短いけど説明が難しいわ。 これを理解するにはデリゲートを知らなければいけないから、今のところは気にしないで。 イベントを作って、イベントがNullじゃなければ、イベントに対応するメソッドを発動する。 と今のところ思っていて。これも後でインドリに説明させるから。
インドリ「ちょっと。ドリィちゃん。デリゲートの説明全てボクに任せるのかい?」
それが何か?
インドリ「・・・わかったよ。」
ということで細かいところは次回説明から最後へ行く。
逃げたか。でも大丈夫。時間ちゃんとデリゲート説明させるわ。
最後の手順はとても単純。1の手順で定義したEventArgsの派生クラスのインスタンスを作って、3の手順で定義したメソッドへ投げるだけ。 これで終わりといいたいところだけど、今回の例の場合派生クラスも変更する必要がある。 ということで私のコードを見なさい。
public class Bird : Animal
{
public Bird( string name, int age ) : base ( name, age ) { }
public override void Move( string destination, string purpose ) {
Console.WriteLine( "バサバサ飛ぶ" );
base.Move( destination, purpose );
}
}
//新しく追加
public class Bear : Animal
{
public Bear( string name, int age ) : base( name, age ) { }
public override void Move( string destination, string purpose ) {
Console.WriteLine( "のしのし歩く" );
base.Move( destination, purpose );
}
}
public class Dog : Animal
{
public Dog( string name, int age ) : base( name, age ) { }
public override void Move( string destination, string purpose ) {
Console.WriteLine( "タッタ走る" );
base.Move( destination, purpose );
}
}
base.Moveとなっているところを注目しなさい。 これは親クラスのメソッドを呼び出しているの。 この文が無いとイベントが発動できないから絶対に付けなさい。 ここまで来たら後はそれを使うだけ。使っている様子を見なさい。そうすれば理解できるはずよ。
//変更した所だけ抜粋
public class Human : Animal
{
public Human( string name, int age ) : base( name, age ) { }
public override void Talk( ) {
Console.WriteLine( "私は{0}。年は20だよ。", this.Name );
}
public override void Move( string destination, string purpose ) {
Console.WriteLine( "テクテク歩く" );
//人は管理しないからbase.Moveなし
}
public void Management( Animal target ) {
target.MoveEvent += new MoveEventHandler( Target_MoveEvent );
}
private void Target_MoveEvent( object sender, MoveEventArgs e ) {
Animal target = (Animal) sender;
if ( target.Name == "インドリ" ) {
Console.WriteLine( "{0}が逃亡するのを確認した。\n" +
"行き先:{1}\n目的:{2}\n",
target.Name, e.Destination, e.Purpose );
} else {
Console.WriteLine( "「{0}さん」が移動するのを確認した。\n" +
"行き先:{1}\n目的:{2}\n",
target.Name, e.Destination, e.Purpose );
}
}
}
class Program
{
static void Main( string[ ] args ) {
Human dre = new Human( "ドリィちゃん", 16 );
dre.Talk( );
dre.Move( "わんくま動物園", "事務仕事" );
Console.WriteLine( "ドリィちゃんが事務仕事を始めます。");
Console.WriteLine( "" );
InDori tori = new InDori( 29 );
dre.Management( tori );
tori.Talk( );
tori.Move( "じゃんぬねっと", "遊び");
Bear naka = new Bear( "中", 34 );
dre.Management( naka );
naka.Talk( );
naka.Move( "東京", "勉強会" );
Dog jyannnu = new Dog( "じゃんぬ", 26 );
dre.Management( jyannnu );
jyannnu.Talk( );
jyannnu.Move( "街", "スイーツ(笑)観察");
}
}
何度かステップ実行して。そうすれば分かるはず。
私は気の聞いたこと言えないからこれでお終い。
そうそう。一つ言い忘れたわ。これはネタだから実在する人物や団体とは一切関係ありません。
笑い流してね。