国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

委托和事件 (2)

2019-11-17 02:35:36
字體:
來源:轉載
供稿:網友

委托和事件 (2) - 事件

事件的由來

上文說到委托的安全性不佳,于是我們要將委托本身私有化,但還要暴露若干方法讓外界使用。其中最重要的必然就是為委托掛接方法和調用委托,以便間接地調用委托所代表方法。那么事件event關鍵字就是c#提供給我們的一個語法糖。他并沒有任何新的東西,只是減少了一些代碼。所以,事件是一種特殊的委托,其特征有:

1 和一個(基底)委托類型合作,當聲明了一個具有該基底委托類型的事件之后,用戶在外部就可以為這個事件掛接方法,其方法類型必須和基底委托類型相同

2 可以將事件視為委托的方法鏈,使用event關鍵字時,該方法鏈是私有的,而使用委托類型名作為關鍵字時,該方法鏈是公共的

3 事件雖然是私有的,但編譯器自動為我們建立了兩個隱藏方法,并重載了+=和-=,使得我們可以不編寫任何額外的代碼,利用+=和-=操作事件上的方法,從而控制當事件觸發時執行什么方法

public class PRogram    {        public static void Main()        {            //創建了一個新的訂閱者            var c = new Car("Mycar", 0, 100);            //還記得委托么,如果methodList是一個CarEngineHandler類型則可以這樣寫            //現在methodList是一個事件類型,這樣寫會報錯            //事件只能出現在+=或者-=的左方,不能出現在等于號的左方            //故此時用戶不能隨意為其賦值,保證了安全            c.methodList = OnCarEvent1;            //這是正確的            c.methodList += OnCarEvent1;            //不能在外部這樣調用一個事件            //c.methodList.Invoke()        }        public static void OnCarEvent1(string msg)        {            Console.WriteLine("***** message from car *****");            Console.WriteLine("=> " + msg);            Console.WriteLine("****************************");        }        public static void OnCarEvent2(string msg)        {            Console.WriteLine("=> " + msg.ToUpper());        }    }    public class Car    {        public string name { get; set; }        public int currentSpeed { get; set; }        public int MaxSpeed { get; set; }        private bool isDead { get; set; }        public delegate void CarEngineHandler(string message);        public event CarEngineHandler methodList;        public Car(string name, int currentSpeed, int MaxSpeed)        {            this.name = name;            this.currentSpeed = currentSpeed;            this.MaxSpeed = MaxSpeed;            this.isDead = false;        }        public void Accel(int delta)        {            //死亡時執行訂閱列表中的方法            if (isDead)            {                if (methodList != null)                    //在內部調用事件和調用委托沒區別                    methodList("Sorry, car is broken");            }            else            {                currentSpeed += delta;                if (currentSpeed >= MaxSpeed) isDead = true;                else Console.WriteLine("Current speed: " + currentSpeed);            }        }    }

事件的代碼規范

微軟為事件設置了代碼規范,和委托相同,這些規范主要有:

1 委托名必須以Handler結尾

2 委托必須有且僅有兩個參數,第一個為object類型的sender,第二個則是一個集成了EventArgs類型的自定義類類型,名字可以自定

那么我們使用代碼規范來重新寫一下上面的例子:

public class Program    {        public static void Main()        {            //創建了一個新的訂閱者            var c = new Car("Mycar", 0, 100);            c.methodList += OnCarEvent1;            for (int i = 0; i < 10; i++)            {                c.Accel(20);            }            Console.ReadKey();        }        public static void OnCarEvent1(object sender, CarEventArgs e)        {            //現在我們知道是誰觸發了事件            Console.WriteLine("***** message from car: " + sender.ToString() + " *****");            Console.WriteLine("=> " + e.message);            Console.WriteLine("****************************");        }    }    public class Car    {        public string name { get; set; }        public int currentSpeed { get; set; }        public int MaxSpeed { get; set; }        private bool isDead { get; set; }        //標準化的委托定義        //sender: 當發生事件時,告知訂閱者是誰觸發了事件        //e: 當發生事件時傳遞的信息(可以自定義一個類繼承EventArgs類,故可以傳遞任意類型的信息)        public delegate void CarEngineHandler(object sender, CarEventArgs e);        public event CarEngineHandler methodList;        public Car(string name, int currentSpeed, int MaxSpeed)        {            this.name = name;            this.currentSpeed = currentSpeed;            this.MaxSpeed = MaxSpeed;            this.isDead = false;        }        public void Accel(int delta)        {            //死亡時執行訂閱列表中的方法            if (isDead)            {                if (methodList != null)                    //在內部調用事件和調用委托沒區別                    methodList(name, new CarEventArgs { message = "Sorry, this car is dead." } );            }            else            {                currentSpeed += delta;                if (currentSpeed >= MaxSpeed) isDead = true;                else Console.WriteLine("Current speed: " + currentSpeed);            }        }    }    //自定義事件發生時發送的信息格式    public class CarEventArgs : EventArgs    {        public string message { get; set; }    }

sender和EventArgs

相信很多人在使用.net進行控件的拖拽時,如果拖拽一個按鈕,然后雙擊它,就會發現代碼多了幾行(省略了無關的):

this.button1.Click += new System.EventHandler(this.button1_Click);
private void button1_Click(object sender, EventArgs e){}

但可能不是所有人都明白那兩個參數是做什么的,反正我在這個方法里寫代碼,然后點擊那個按鈕,編譯器就會執行到這里面的代碼。其實這正是符合微軟命名規范的一個事件的例子。

1. 在初始化時,為這個對象的Click屬性(注意該屬性的類型是一個事件,他的基底委托是EventHandler類型的)綁定了button1_Click方法。此時如果這個事件被調用,那么就會執行button1_Click方法的代碼。

EventHandler 是C#控件中最常見的委托,它沒有返回類型:

public delegate void EventHandler (Object sender, EventArgs e)

我們注意到,這個委托正好和button1_Click方法簽名相同,也就是說,我們可以將button1_Click方法加入到委托的方法鏈中。而在這里,方法鏈就是事件類型變量Click。

2. 當單擊按鈕時,經過一系列的消息輪詢最終系統捕獲到了你的單擊動作,再經過一系列處理,最后到了Control.OnClick(System.EventArgs e)方法

3. 在這個方法里調用事件

        protected virtual void OnClick(EventArgs e)        {            //從Events委托集合中取出名為EventClick的委托            EventHandler handler = (EventHandler)base.Events[EventClick];            //如果不為空則執行這個委托上的方法,也就是button1_Click            if (handler != null)            {                //this就是button1                handler(this, e);            }        }

大略的整個過程就是:

1. 你的點擊動作被windows捕獲,windows把這個動作(this.button1.Click)作為系統消息發送給程序(底層消息輪詢機制)

2. 程序從自己的消息隊列中不斷的取出消息,并在消息循環中尋找對應的處理方式

3. 對于這個消息,其sender(事件的來源)就是這個按鈕,發送的消息全部在e里面,在某些事件里,e用處不大,比如在MouseEventArgs的Mouse事件中,可以看到e包括mouse的坐標值等,以供你的程序使用

4. 因為this.button1.Click掛接了方法button1_Click,故執行這里面的代碼

所以說實際上當單擊按鈕時,其實編譯器已經幫我們做了很多事情,例如委托的建立,事件的掛接和執行,這些都已經被封裝到你根本就不需要知道也可以編寫出來成功執行的代碼的程度了。那么委托和事件這個話題差不多就結束了(在c#1.0這個層面上)。在更高版本的c#中,委托和事件被包裝的更加簡便易用了,基于泛型的委托action和func的出現,更是(基本上)完全替代了原生的委托delegate。這些精彩的內容當然要等待到介紹c#2和3的時候一塊講述。

參考資料

http://m.survivalescaperooms.com/leslies2/archive/2012/03/22/2389318.html

http://www.tracefact.net/csharp-programming/delegates-and-events-in-csharp.aspx

http://m.survivalescaperooms.com/zhili/archive/2012/10/29/ButtonClickEvent.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 喜德县| 乌拉特后旗| 蕉岭县| 长乐市| 海兴县| 邢台县| 郁南县| 垫江县| 远安县| 明光市| 墨江| 新宁县| 邯郸市| 师宗县| 调兵山市| 雅江县| 逊克县| 绥宁县| 将乐县| 新昌县| 宜章县| 连江县| 大同市| 融水| 陇南市| 清新县| 广丰县| 揭阳市| 陈巴尔虎旗| 固安县| 永德县| 壶关县| 吴江市| 东兴市| 红安县| 普宁市| 定州市| 碌曲县| 米泉市| 富顺县| 孙吴县|