本当は、Moq の続きの記事を書こうと思ったのだが、Moq の次の対象が、Event だった。いろいろな記事やリファレンスを読んだけど、正直複雑で意味がわからなかったので、調べてみた。
多分めっちゃ簡単な実装をしてみた。The Simplest C# Events Example Imaginableでやっと理解できたので、それを自分なりに実装してみた。
Event を理解するクソガキアプリ
これはクソガキ通報アプリだ。クソガキ何かをしているのを、警察が観察しているけど、クソガキが法にふれたら刑務所にぶち込むというアプリだ。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kusogaki
{
public class Kusogaki
{
public event CriminalHandler Criminal;
public EventArgs e = null;
public delegate void CriminalHandler(Kusogaki k, EventArgs e);
public void Observe()
{
while (true)
{
Console.WriteLine("#[Kusogaki] クソガキの行動を報告してください。");
var action = Console.ReadLine();
if (action == "万引き") {
if (Criminal != null)
{
Console.WriteLine($"#[Kusogaki] クソガキは {action} した。そらあかんやろ。通報や。");
Criminal(this, e); // 1. ここでイベント発生
}
} else
{
Console.WriteLine($"#[Kusogaki] クソガキは {action} したけどまあいいやろ。");
}
}
}
}
public class Police
{
public void Subscribe(Kusogaki k)
{
k.Criminal += new Kusogaki.CriminalHandler(Arrest); // 2. クソガキ側のイベントハンドラに警察のメソッドを登録
}
private void Arrest(Kusogaki k, EventArgs e) // 3. 実行されるメソッド
{
Console.WriteLine($"#[Police] クソガキを連行します。");
}
}
class Program
{
static void Main(string[] args)
{
var kusogaki = new Kusogaki();
var police = new Police();
police.Subscribe(kusogaki); // 0. イベント発生前に、クソガキを登録
kusogaki.Observe();
}
}
}
コンソールアプリなので、理解しやすいだろう。結局ポイントは、イベントが発生するとどうなるかだ。イベント発生前に、0. の箇所で、クソガキの、Criminal Handler に、Police 側の Arrest メソッドを登録しておく。(2.)実際に、1. でイベントが発生すると、Event Handler に登録された、メソッドに処理が委譲される。
#[Kusogaki] クソガキの行動を報告してください。
鼻垂らした
#[Kusogaki] クソガキは 鼻垂らした したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
おばちゃんバカにした
#[Kusogaki] クソガキは おばちゃんバカにした したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
万引き
#[Kusogaki] クソガキは 万引き した。そらあかんやろ。通報や。
#[Police] クソガキを連行します。
クソガキがしっかり連行された。
"+=" の謎
ちなみにメソッド登録時にこんなコードになっている。
k.Criminal += new Kusogaki.CriminalHandler(Arrest);
リファレンスを見てもよくわからないが、どうやらリストのように、ハンドラにいくつかのメソッドを登録できるっぽい。試してみよう。クソガキを連行して、刑務所にぶち込もう。
public class Police
{
public void Subscribe(Kusogaki k)
{
k.Criminal += new Kusogaki.CriminalHandler(Arrest);
k.Criminal += new Kusogaki.CriminalHandler(Imprison);
}
private void Arrest(Kusogaki k, EventArgs e)
{
Console.WriteLine($"#[Police] クソガキを連行します。");
}
private void Imprison(Kusogaki k, EventArgs e)
{
Console.WriteLine($"#[Police] 懲役3年。お勤め頑張るんだぞ。");
}
}
実行してみる。
#[Kusogaki] クソガキの行動を報告してください。
ハゲおやじをバカにした
#[Kusogaki] クソガキは ハゲおやじをバカにした したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
屁をこいだ
#[Kusogaki] クソガキは 屁をこいだ したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
万引き
#[Kusogaki] クソガキは 万引き した。そらあかんやろ。通報や。
#[Police] クソガキを連行します。
#[Police] 懲役3年。お勤め頑張るんだぞ。
イベントを監視することで、無事、クソガキを逮捕できました。
犯行時間を加える
イベントが実行されるときに、何かの値を渡したいかもしれません。試しに、犯行時間を渡せるようにします。
public class TimeOfCrime : EventArgs
{
public DateTime Time
{
get; set;
}
}
こんな感じに EventArgs を継承したクラスを作ります。それを、先ほど EventArgs と書いていたところと置き換えます。
public class Kusogaki
{
public event CriminalHandler Criminal;
public TimeOfCrime e = null; // 書き換え
public delegate void CriminalHandler(Kusogaki k, TimeOfCrime e); // 書き換え
public void Observe()
{
while (true)
{
Console.WriteLine("#[Kusogaki] クソガキの行動を報告してください。");
var action = Console.ReadLine();
if (action == "万引き") {
if (Criminal != null)
{
Console.WriteLine($"#[Kusogaki] クソガキは {action} した。そらあかんやろ。通報や。");
TimeOfCrime e = new TimeOfCrime(); // 書き換え
e.Time = DateTime.Now;
Criminal(this, e);
}
} else
{
Console.WriteLine($"#[Kusogaki] クソガキは {action} したけどまあいいやろ。");
}
}
}
}
public class Police
{
public void Subscribe(Kusogaki k)
{
k.Criminal += new Kusogaki.CriminalHandler(Arrest);
k.Criminal += new Kusogaki.CriminalHandler(Imprison);
}
private void Arrest(Kusogaki k, TimeOfCrime e) // 書き換え
{
Console.WriteLine($"#[Police] クソガキを連行します。犯行時間 {e.Time}"); // 書き換え
}
private void Imprison(Kusogaki k, TimeOfCrime e) // 書き換え
{
Console.WriteLine($"#[Police] 懲役3年。お勤め頑張るんだぞ。");
}
}
:
実行結果はこの通り。予想どおり!
#[Kusogaki] クソガキの行動を報告してください。
大阪のおばちゃんのシャツをバカにした
#[Kusogaki] クソガキは 大阪のおばちゃんのシャツをバカにした したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
ウォーターフォールをやった
#[Kusogaki] クソガキは ウォーターフォールをやった したけどまあいいやろ。
#[Kusogaki] クソガキの行動を報告してください。
万引き
#[Kusogaki] クソガキは 万引き した。そらあかんやろ。通報や。
#[Police] クソガキを連行します。犯行時間 2017/07/26 15:55:14
#[Police] 懲役3年。お勤め頑張るんだぞ。
無事クソガキが逮捕されて、犯行時間が記録されて、尚且つ皆さんの Event の理解につながれば幸いです。
コードは、GitHubに置いておきました。