第十四章 事件

14.1 發(fā)布者/訂閱者

  • 發(fā)布者(publisher):發(fā)布某個(gè)事件的類(lèi)或結(jié)構(gòu),其他類(lèi)可以在該事件發(fā)生時(shí)得到通知。
  • 訂閱者(subscriber):注冊(cè)并在事件發(fā)生時(shí)得到通知的類(lèi)或結(jié)構(gòu)
  • 事件處理程序(event handler) :由訂閱者注冊(cè)到事件的方法,在發(fā)布者觸發(fā)事件時(shí)執(zhí)行。事件處理程序方法可以定義在事件所在的類(lèi)或結(jié)構(gòu)中,也可以定義在不同的類(lèi)或結(jié)構(gòu)中。
  • 觸發(fā)(raise)事件 調(diào)用(invoke)或觸發(fā)(fire)事件的術(shù)語(yǔ):當(dāng)事件觸發(fā)時(shí),所有注冊(cè)到它的方法都會(huì)被依次調(diào)用。

有關(guān)事件的私有委托

  • 事件提供了對(duì)它的私有控制委托的結(jié)構(gòu)化訪問(wèn)。即你無(wú)法直接訪問(wèn)委托。
  • 事件中可用的操作比委托少,對(duì)于事件我們只可以添加、刪除或調(diào)用事件處理程序。
  • 事件被觸發(fā)時(shí),它調(diào)用委托來(lái)依次調(diào)用調(diào)用列表中的方法。

14.2 源代碼組件概覽

一個(gè)完整的組件由5部分組成:

  • 委托類(lèi)型聲明:事件和事件處理程序必須有共同的簽名和返回類(lèi)型,他們通過(guò)委托類(lèi)型進(jìn)行描述。
  • 事件處理程序聲明:訂閱者類(lèi)中會(huì)在事件觸發(fā)時(shí)執(zhí)行的方法聲明??梢允秋@式命名的方法,也可以是匿名方法或Lambda表達(dá)式。
  • 事件聲明:發(fā)布者類(lèi)必須聲明一個(gè)訂閱者類(lèi)可以注冊(cè)的事件成員。當(dāng)聲明的事件為public時(shí),稱(chēng)為發(fā)布了事件。
  • 事件注冊(cè):訂閱者必須訂閱事件才能在它被觸發(fā)時(shí)得到通知。
  • 觸發(fā)事件的代碼:發(fā)布者類(lèi)中“觸發(fā)”事件并導(dǎo)致調(diào)用注冊(cè)的所有事件處理程序的代碼。
    使用事件時(shí)的5個(gè)源代碼組件
static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);
            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }
//發(fā)布者類(lèi)
        class Incrementer
        {
            public delegate void Handler();//委托類(lèi)型聲明
            public event Handler CountADozen;//事件聲明

            public void DoCount()
            {
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen();//觸發(fā)事件代碼
                    }
                }
            }
        }
//訂閱者類(lèi)
        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;//事件注冊(cè)
            }

            void IncrementerDozensCount()//事件處理程序聲明
            {
                DozensCount++;
            }
        }
    }

14.6 標(biāo)準(zhǔn)事件的用法

程序事件的異步處理是使用C#事件的絕佳場(chǎng)景。WindowsGUI編程廣泛地使用了事件,.NET框架提供了一個(gè)標(biāo)準(zhǔn)模式。事件使用的標(biāo)準(zhǔn)模式的根本是System命名空間聲明的EventHandler委托類(lèi)型。
public delegate void EventHandler(object sender, EventArgs e);

  • 第一個(gè)參數(shù)用來(lái)保存觸發(fā)事件的對(duì)象的引用。由于是object類(lèi)型,可以匹配任何類(lèi)型的實(shí)例。
  • 第二個(gè)參數(shù)用來(lái)保存狀態(tài)信息,指明什么類(lèi)型適用于該應(yīng)用程序;
  • 返回類(lèi)型是 void
  • EventArgs設(shè)計(jì)為不能傳遞任何數(shù)據(jù)。它用于不需要傳遞數(shù)據(jù)的事件處理程序——通常會(huì)被忽略。
  • 如果要傳遞數(shù)據(jù),必須聲明一個(gè)派生自EventArgs的類(lèi),使用合適的字段來(lái)保存需要傳遞的數(shù)據(jù)。

修改上述程序使之使用標(biāo)準(zhǔn)EventHandler委托:

static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);
            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }

        class Incrementer
        {
            public event EventHandler CountADozen;//使用系統(tǒng)定義的EventHandler委托

            public void DoCount()
            {
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen(this, null);//觸發(fā)事件時(shí)使用EventHandler的參數(shù)
                    }
                }
            }
        }

        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;
            }

            void IncrementerDozensCount(object sender, EventArgs e)//事件處理程序的簽名必須與委托的簽名匹配
            {
                DozensCount++;
            }
        }
    }
14.6.1 通過(guò)擴(kuò)展EventArgs來(lái)傳遞參數(shù)

要向事件處理程序的第二個(gè)參數(shù)傳入數(shù)據(jù),需要聲明一個(gè)派生自EventArgs的自定義類(lèi),可以保存要傳的數(shù)據(jù)。

static class Program
    {
        static void Main()
        {
            Incrementer incrementer = new Incrementer();
            Dozens dozensCounter = new Dozens(incrementer);

            incrementer.DoCount();
            Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
            Console.ReadKey();
        }

        public class IncrementerEventArgs : EventArgs//自定義類(lèi)派生自EventArgs
        {
            public int IterationCount { get; set; }//存儲(chǔ)一個(gè)整數(shù)
        }

        class Incrementer
        {
            public event EventHandler<IncrementerEventArgs> CountADozen;//使用、自定義類(lèi)的泛型委托

            public void DoCount()
            {
                IncrementerEventArgs args = new IncrementerEventArgs();//自定義類(lèi)對(duì)象
                for (int i = 1; i < 100; i++)
                {
                    if (i % 12 == 0 && CountADozen != null)
                    {
                        CountADozen(this, args);//觸發(fā)事件時(shí)傳遞參數(shù)
                    }
                }
            }
        }

        class Dozens
        {
            public int DozensCount { get; private set; }

            public Dozens(Incrementer incrementer)
            {
                DozensCount = 0;
                incrementer.CountADozen += IncrementerDozensCount;
            }

            void IncrementerDozensCount(object sender, IncrementerEventArgs e)//事件處理程序的簽名必須與委托的簽名匹配
            {
                Console.WriteLine("Incremented at iteration: {0} in {1}", e.IterationCount, sender.ToString());

                DozensCount++;
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • #1. 委托1.1 聲明委托1.2 使用委托1.3 簡(jiǎn)單委托示例1.4 Action<T>和Func<T>委托1....
    MrDecoder閱讀 747評(píng)論 0 2
  • 一、理解事件事件采用發(fā)布/訂閱模型,其中發(fā)行者決定在什么情況下引發(fā)事件,而訂戶決定為響應(yīng)事件而執(zhí)行的操作。事件可以...
    CarlDonitz閱讀 354評(píng)論 0 0
  • 網(wǎng)上講C#委托和事件的博文已經(jīng)非常多了,其中也不乏一些深入淺出、條理清晰的文章。我之所以還是繼續(xù)寫(xiě),主要是借機(jī)整理...
    丑小丫大笨蛋閱讀 1,197評(píng)論 0 5
  • 定義:委托是一種引用類(lèi)型,表示對(duì)具有特定參數(shù)列表和返回類(lèi)型的方法的引用。 在實(shí)例化委托時(shí),你可以將其實(shí)例與任何具有...
    52718閱讀 7,766評(píng)論 3 14
  • 事件 事件含義 事件由對(duì)象引發(fā),通過(guò)我們提供的代碼來(lái)處理。一個(gè)事件我們必須訂閱(Subscribe)他們,訂閱一個(gè)...
    天堂邁舞閱讀 3,155評(píng)論 1 7

友情鏈接更多精彩內(nèi)容