C# 入門 & 実践 / C sharp

4-29. イベント - 3 - 非同期で実行&コールバックで返り値を取る!


MyHandlerの呼び出しを一つずつ順番に非同期 ( BeginInvoke ) で呼び出す。
Callbackメソッドを設定し返り値を取るよう設定!( EndInvoke )
出力は Hello Goodbye ともに60のときのみ

    // イベント情報
    class BbEventArgs : EventArgs 
    {
        private readonly int cnt = 0;
        public BbEventArgs( int cnt )
        {
            this.cnt = cnt; 
        }

        public int Cnt
        {
            get { return cnt; }
        }
    }

    // メインで動くクラス。
    class BbEvent
    {
        private int mycnt = 0;
        
        // 独自のイベント情報を利用するためのハンドラー
        // 返り値 int を設定。
        public delegate int BbHandler(object o, BbEventArgs e);
        // イベントハンドラーのデリゲート宣言です。。。
        public event BbHandler MyHandler;

        // イベントを発生させるためのメソッド。
        protected virtual void OnMyHandler( BbEventArgs e )
        {
            if (MyHandler != null)
            {
                // 今までは一回で処理していた。
                // MyHandler(this, e);
                // 非同期で処理させる。
                foreach (BbHandler del in MyHandler.GetInvocationList() )
                {
                    Console.WriteLine("メソッド開始! : {0} ", del.Method.ToString());
                    del.BeginInvoke(this, e, new AsyncCallback(ResultsBack), del);
                }
            }
        }

        // コールバック用メソッド
        // デリゲートメソッドが終了したら呼ばれる!
        private void ResultsBack(IAsyncResult iar)
        {
            // BbHandlerにキャスト
            BbHandler bh = (BbHandler)iar.AsyncState;
            // 返り値を見る。
            int result = bh.EndInvoke(iar);

            Console.WriteLine("メソッド終了 : {0} : ret : {1}", bh.Method.ToString() ,result);
        }

        // このメソッド内でイベント呼び出しがあります。
        public void Run()
        {
            int i = 1;
            for (;;)
            {
                mycnt++;

                // 10 ミリ秒休憩
                Thread.Sleep( 10 );

                // 30 で割り切れるときにイベント発生
                if ((i % 30) == 0)
                {
                    // イベントオブジェクト生成
                    BbEventArgs be = new BbEventArgs(i);
                    // イベントを発生させる!
                    OnMyHandler(be);
                }
                i++;
                if (i > 100)
                {
                    i = 1;
                }

                if (mycnt > 100)
                {
                    Console.WriteLine("終了");
                    // 300 ループして終わる
                    return;
                }
            }
        }
    }

    // イベント発生時の動作 1
    class BbHello
    {
        private int mycnt = 0;
        // Subscribe :メソッドを設定
        public void setMethod(BbEvent e)
        {
            e.MyHandler += new BbEvent.BbHandler(SayHello);
        }

        // 
        public int SayHello(Object o, BbEventArgs e)
        {
            // 10 ミリ秒待ちます!
            Thread.Sleep(10);
            mycnt++;
            if (e.Cnt == 60)
            {
                Console.WriteLine("SayHello : mycnt = {1} / イベント情報 cnt = {0}", e.Cnt, mycnt);
                return 1;
            }
            else
            {
                // 出力しない場合 0 を返す
                return 0;
            }
        }
    }
    // イベント発生時の動作 1
    class BbGoodbye
    {
        private int mycnt = 0;
        // Subscribe :メソッドを設定
        public void setMethod(BbEvent e)
        {
            // e.MyHandler += new BbEvent.BbHandler(SayGoodbye);
            e.MyHandler += delegate(Object o, BbEventArgs ev)
                {
                    mycnt++;
                    if (ev.Cnt == 60)
                    {    
                        Console.WriteLine("SayGoodbye : mycnt = {1} / イベント情報 cnt = {0}", ev.Cnt, mycnt);
                        return 1;
                    }
                    else
                    {
                        // 出力しない場合 0 を返す
                        return 0;
            
                    }
                };
        }
    }

    class MyTester
    {
        static void Main()
        {
            
            // メイン:イベント発行を行うクラス
            BbEvent be = new BbEvent();

            // イベント発行時の実行メソッド
            BbHello bh = new BbHello();
            BbGoodbye bg = new BbGoodbye();

            // subscribe : 実行メソッドをセットする
            bh.setMethod(be);
            bg.setMethod(be);

            // Run を実行!
            be.Run();
        }
    }


非同期で開始



SayHelloの後にSayGoodbyeを設定したので、その順番どおりに開始&終了している。
非同期であることはわかり難い^-^;
返り値はちゃんと取れていますね。

メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
SayHello : mycnt = 2 / イベント情報 cnt = 60
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 1
SayGoodbye : mycnt = 2 / イベント情報 cnt = 60
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 1
メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 0
終了


ここでSayHelloメソッド内にSleep( 10 )を入れてみる。

メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
SayGoodbye : mycnt = 2 / イベント情報 cnt = 60
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 1
SayHello : mycnt = 2 / イベント情報 cnt = 60
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 1
メソッド開始! : Int32 SayHello(System.Object, HelloWorld.BbEventArgs)
メソッド開始! : Int32 b__0(System.Object, HelloWorld.BbEventArgs)
メソッド終了 : Int32 b__0(System.Object, HelloWorld.BbEventArgs) : ret : 0
メソッド終了 : Int32 SayHello(System.Object, HelloWorld.BbEventArgs) : ret : 0
終了

予定通りSayHelloが先に呼ばれているのに終了は遅くなっていますね!^-^。





4-28. イベント - 2 - 独自のイベントデータを使用する « 4. C# 入門 Level 2


C# 入門 & 実践 / C sharp