LoginSignup
21
26

More than 5 years have passed since last update.

C# の Event をクソガキで理解する。

Last updated at Posted at 2017-07-26

本当は、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に置いておきました。

21
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
26