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