大白話系列之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結尾。

這就是微軟編碼的規範,當然這不僅僅是規則,而是在這種規則下使程序有更大的靈活性,那我們就繼續重構第三講的例子,讓他符合微軟的規範。

ExpandedBlockStart.gif代碼
    //所有訂閱者【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

 

ExpandedBlockStart.gif代碼
    //---本例場景爲當用戶從銀行賬號裏取出錢後,馬上通知電子郵件和發手機短信---
    
//本例中的訂閱者,也就是觀察者是電子郵件與手機
    
//發佈者,也就是被監視對象是銀行賬號


    
//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("[email protected]""18868789776",amount);
            
//初始化訂閱系統
            SubscribSystem subject = new SubscribSystem(new BankAccount(), user);
            Console.ReadKey();
        }
    }

 

 

 控制檯

 

網上還有個熱水器燒水的OBSERVER PATTERN 也是蠻經典的,大家可以看看。

下一講我們要講講,在我們的日常的MES系統開發中,到底在什麼場景用到委託事件,畢竟我們學了這樣的技術,我們必須要用起來,這才有價值嘛!

呵呵!下講,將會更加精彩!

 

 

 

首頁推薦不能放,我就放這裏好了

大白話系列之C#委託與事件講解(序言)

大白話系列之C#委託與事件講解(一)  

大白話系列之C#委託與事件講解(二)

 

 

推薦2篇文章,是關於人生的

 爲什麼我們做不到【領導篇】

 爲什麼我們做不到【員工篇】

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章