大白话系列之C#委托与事件讲解(三)
今天我接著上面的3篇文章來講一下,為什么我們在日常的編程活動中遇到這么多sender,EventArgs e 參數:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
}
protected void grdBill_RowDataBound(object sender, GridViewRowEventArgs e)
{
???????????
}
那他們到底表示什么呢?
在回答上面的問題之前,我們先搞懂 .Net Framework的編碼規范:
一、委托類型的名稱都應該以EventHandler結束。?
二、委托的原型定義:有一個void返回值,并接受兩個輸入參數:一個Object 類型,一個 EventArgs類型(或繼承自EventArgs)。?
三、事件的命名為 委托去掉 EventHandler之后剩余的部分。?
四、繼承自EventArgs的類型應該以EventArgs結尾。
這就是微軟編碼的規范,當然這不僅僅是規則,而是在這種規則下使程序有更大的靈活性,那我們就繼續重構第三講的例子,讓他符合微軟的規范。
代碼
????//所有訂閱者【Subscriber】感興趣的對象,也就是e,都要繼承微軟的EventArgs
????//本例中訂閱者【也稱觀察者】MrMing,MrZhang他們感興趣的e對象,就是雜志【magazine】
????public?class?PubEventArgs?:?EventArgs
????{
????????public?readonly?string?magazineName;
????????public?PubEventArgs()
????????{
?
????????}
????????public?PubEventArgs?(string?magazineName)
????????{
???????????this.magazineName?=?magazineName;
????????}
????}
????//發布者(Publiser)
????public?class?Publisher
????{
????????//聲明一個出版的委托
????????//這里多了一個參數sender,它所代表的就是Subject,也就是監視對象,本例中就是Publisher
????????public?delegate?void?PublishEventHander(object?sender?,PubEventArgs?e);
????????//在委托的機制下我們建立以個出版事件
????????public?event?PublishEventHander?Publish;
????????//聲明一個可重寫的OnPublish的保護函數
????????protected?virtual?void?OnPublish(PubEventArgs?e)
????????{
????????????if?(Publish?!=?null)
????????????{
????????????????//Sender?=?this,也就是Publisher
????????????????this.Publish(this,?e);
????????????}
????????}
????????//事件必須要在方法里去觸發
????????public?void?issue(string?magazineName)
????????{
????????????OnPublish(new?PubEventArgs(magazineName));
????????}
????}
????//Subscriber?訂閱者
????public?class?MrMing
????{
????????//對事件感興趣的事情
????????public?static?void?Receive(object?sender,PubEventArgs?e)
????????{
????????????Console.WriteLine("嘎嘎,我已經收到最新一期的《"+e.magazineName+"》啦!!");
????????}
????}
????public?class?MrZhang
????{
????????//對事件感興趣的事情
????????public?static?void?Receive(object?sender,?PubEventArgs?e)
????????{
????????????Console.WriteLine("幼稚,這么大了,還看《火影忍者》,SB小明!");
????????????Console.WriteLine("這個我定的《"+e.magazineName+"》,哇哈哈!");
????????}
????}
????class?Story
????{
????????public?static?void?Main(string[]?args)
????????{
????????????//實例化一個出版社
????????????Publisher?publisher?=?new?Publisher();
????????????Console.Write("請輸入要發行的雜志:");
????????????string?name?=?Console.ReadLine();
????????????if?(name?==?"火影忍者")
????????????{
????????????????//給這個出火影忍者的事件注冊感興趣的訂閱者,此例中是小明
????????????????publisher.Publish?+=?new?Publisher.PublishEventHander(MrMing.Receive);
????????????????//發布者在這里觸發出版火影忍者的事件
????????????????publisher.issue("火影忍者");
????????????}
????????????else
????????????{
????????????????//給這個出火影忍者的事件注冊感興趣的訂閱者,此例中是小明[另一種事件注冊方式]
????????????????publisher.Publish?+=?MrZhang.Receive;
????????????????publisher.issue("環球日報");
????????????}
????????????Console.ReadKey();
????????}
????}
?
輸入火影忍者后,觸發小明訂閱的事件
顯示
通過例子我再做一次說明,其實我們不用把Sender,e想的過于可怕
一、委托聲明原型中的Object類型的參數代表了Subject,也就是監視對象,在本例中是 Publisher(出版社)。。?
二、EventArgs 對象包含了Observer所感興趣的數據,在本例中是雜志。
?
?
?大家先休息休息,讓大腦放松放松,先讓我們看句名人名言:
?很多事情就像看A片,看的人覺得很爽,做的人未必!
?“中國人的勵志和國外的勵志存在非常大的不同,中國的勵志比較鼓勵人立下大志愿,臥薪嘗膽,有朝一日成富成貴。而國外的勵志比較鼓勵人勇敢面對現實生活,面對普通人的困境,雖然結果也是成富成貴,但起點不一樣,相對來說,我覺得后者在操作上更現實,而前者則需要用999個失敗者來堆砌一個成功者的故事。”
?
好了,我們接著講我們的委托與事件,其實如果大家對設計模式精通的話,其實他們關聯的是觀察者(Observer)模式,這里我就不再描述什么是觀察者模式了,只是簡單講一下他們的關聯:
在C#的event中,委托充當了抽象的Observer接口,而提供事件的對象充當了目標對象。委托是比抽象Observer接口更為松耦合的設計。
如果看不懂的話也沒關系,當大家OO達到一定程度了,自然而然就會明白。
?
最后我們來看一個我們日常最最常用的觀察者模式:
場景:當我們用信用卡刷完錢的時候,我們就會接收到手機短信,或者是電子郵件,其實這就是Observer pattern
?
代碼
??? //---本例場景為當用戶從銀行賬號里取出錢后,馬上通知電子郵件和發手機短信---
????//本例中的訂閱者,也就是觀察者是電子郵件與手機
????//發布者,也就是被監視對象是銀行賬號
????//Obverser電子郵件,手機關心的對象e?,分別是郵件地址、手機號碼、取款金額
????public?class?UserEventArgs?:?EventArgs
????{
????????public?readonly?string?emailAddress;
????????public?readonly?string?mobilePhone;
????????public?readonly?string?amount;
????????public?UserEventArgs(string?emailAddress,?string?mobilePhone,string?amount)
????????{
????????????this.emailAddress?=?emailAddress;
????????????this.mobilePhone?=?mobilePhone;
????????????this.amount?=?amount;
????????}
????}
????//發布者,也就是被監視的對象-銀行賬號
????class?BankAccount
????{
????????//聲明一個處理銀行交易的委托
????????public?delegate?void?ProcessTranEventHandler(object?sender,?UserEventArgs?e);
????????//聲明一個事件
????????public?event?ProcessTranEventHandler?ProcessTran;
????????protected?virtual?void?OnProcessTran(UserEventArgs?e)
????????{
????????????if?(ProcessTran?!=?null)
????????????{
????????????????ProcessTran(this,?e);
????????????}
????????}
????????public?void?Prcess(UserEventArgs?e)
????????{
????????????OnProcessTran(e);
????????}
????}
????//觀察者Email
????class?Email
????{
????????public?static?void?SendEmail(object?sender,?UserEventArgs?e)
????????{
????????????Console.WriteLine("向用戶郵箱"?+?e.emailAddress?+?"發送郵件:您在"+System.DateTime.Now.ToString()+"取款金額為"+e.amount);
????????}
????}
????//觀察者手機
????class?Mobile
????{
????????public?static?void?SendNotification(object?sender,?UserEventArgs?e)
????????{
????????????Console.WriteLine("向用戶手機"?+?e.mobilePhone?+?"發送短信:您在"?+?System.DateTime.Now.ToString()?+?"取款金額為"?+?e.amount);
????????}
????}
????//訂閱系統,實現銀行系統訂閱幾個Observer,實現與客戶端的松耦合
????class?SubscribSystem
????{
????????public?SubscribSystem()
????????{
?
????????}
????????public?SubscribSystem(BankAccount?bankAccount,?UserEventArgs?e)
????????{
????????????//現在我們在銀行賬戶訂閱2個,分別是電子郵件和手機短信
????????????bankAccount.ProcessTran?+=?new?BankAccount.ProcessTranEventHandler(Email.SendEmail);
????????????bankAccount.ProcessTran?+=?new?BankAccount.ProcessTranEventHandler(Mobile.SendNotification);
????????????bankAccount.Prcess(e);
????????}
????}
????class?Client
????{
????????public?static?void?Main(string[]?args)
????????{
????????????Console.Write("請輸入您要取款的金額:");
????????????string?amount?=?Console.ReadLine();
????????????Console.WriteLine("交易成功,請取磁卡。");
????????????//初始化e
????????????UserEventArgs?user?=?new?UserEventArgs("jinjiangbo2008@163.com",?"18868789776",amount);
????????????//初始化訂閱系統
????????????SubscribSystem?subject?=?new?SubscribSystem(new?BankAccount(),?user);
????????????Console.ReadKey();
????????}
????}
?
?
?控制臺
?
網上還有個熱水器燒水的OBSERVER PATTERN 也是蠻經典的,大家可以看看。
from:?https://www.cnblogs.com/wudiwushen/archive/2010/04/21/1717378.html
總結
以上是生活随笔為你收集整理的大白话系列之C#委托与事件讲解(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大白话系列之C#委托与事件讲解(二)
- 下一篇: 大白话系列之C#委托与事件讲解大结局