C# eventのオーバーライドと基底クラスで発生するイベントの処理

C#のeventはvirtualが宣言できて、派生クラスでoverrideできますが、そのオーバーライドされたイベントに登録したイベントハンドラを基底クラス側から呼び出せません。これはeventは宣言された同一クラス内でのみ発生させることができると言うC#の言語仕様なので当たり前と言えば当たり前の動作なのですが、適切な処理をしていないがために基底クラス側でイベントを発生させたときにExceptionが発生してしまったりと言うことがあります。(別の言い方を知れば派生クラスから基底クラスのイベントを発生させることができません。)

まぁ頭の悪い子(俺)はそれでずっとうじうじ悩んだりするわけです。

具体的にはイベントをオーバライドしたら、そのオーバーライドしたイベントの基底クラスのイベントのイベントハンドラを用意し、そのイベントハンドラで、オーバーライドしたイベントを呼び出します。ようはイベントが伝達できるようにすればいいわけですねって、オーバーライドって文字がたくさん出てきて何かよくわかりませんね。と言うことでサンプルを以下にのせます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EventTest
{
    class Program
    {
        static void Main(string[] args) {
            Test test = new Test();
            test.TestEvent += new EventHandler(test_TestEvent);
            test.Fire();
            test.BaseFire();
            Console.Read();
        }

        static void test_TestEvent(object sender, TestEventArgs e) {
            Console.WriteLine(e.Message);
        }
    }

    //基底クラス
    public class TestBase
    {
        //イベントをvirtualで宣言する。
        internal virtual event EventHandler TestEvent;
        //イベントを発生させる
        public void BaseFire() {
            TestEventArgs args = new TestEventArgs("Fired on Base class");
            TestEvent(this, args);//派生クラス側で処理がないとイベントを発生できないので、ここでExceptionが発生する。
        }

    }

    //派生クラス
    public class Test : TestBase
    {
        internal override event EventHandlerTestEvent;

        public Test() {
            //基底クラスのイベントにイベント伝達用のイベントハンドラを登録する。
            base.TestEvent += new EventHandler(Test_TestEvent);
        }
        //イベント伝達用のイベントハンドラ
        void Test_TestEvent(object sender, TestEventArgs e) {
            //利用先に基底クラスのイベントを伝達する
            this.TestEvent(sender, e);
        }
        //イベントを発生させる
        public void Fire() {
            TestEvent(this, new TestEventArgs("Fired on Extended class"));
        }
    }

    public class TestEventArgs : EventArgs
    {
        public TestEventArgs(string message) {
            this.Message = message;
        }
        public string Message { get; set; }
    }
}

実行結果

Fired on Extended class
Fired on Base class

当たり前と言えば当たり前のコードなんですがeventのvirtual / override含めて書籍やネットにあまりサンプルが無いようなので載せてみました。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください