【C#系列】你應該知道的委託和事件

來源:互聯網
上載者:User

標籤:+=   自動   機制   copy   實作類別   分享圖片   中介   介面編程   封裝   

 

本篇文章更適合具有一定開發經驗,一定功底,且對底層代碼有所研究的朋友!!!

 

本篇文章主要採用理論和代碼執行個體相結合方式來論述委託和事件,涉及到一些邊界技術,如軟體架構的OCP原則(開-閉原則),

軟體架構解耦,設計模式(Sender-Order)和事件驅動模型,有一定難度和深度,不適合初級者。

第一部份   委託

關於委託內容,主要圍繞來論述。

 一   委託是什麼(what)

(一)委託產生的背景之一

1.我們先來假設這樣一個情景需求:

   設計一個系統,使其滿足如下條件:

   (1)當前,只有中國人和英國人使用該系統;

   (2)向系統輸入使用者名稱和相應的語言,將產生相應語言的問候語;

      

  (3)後期,可能會有其他國家語言加入該系統(系統變化的部分) ;

 2.技術方案實現

關於技術方案實現,我們可以採用中的三種方式之一。

為了更好地敘述委託,我們分別實現三種技術方案,並找出它們的關係。

 2.1 一般實現

Code(控制台程式)

 View Code

 Result

分析

 

2.2用介面實現

如上,我們分析了方案一中的問題,為了更好地解決方案一存在的問題,我們採用面向介面編程的形式來實現。

2.2.1  什麼是面向介面編程?

面向介面編程,主要是解決軟體架構設計中“動靜問題”,即封裝不變(靜),剝離變化(抽出變化)。

 Code:

 View Code

result

分析:

(1)如上,我們將變化因子"語言"剝離出來,形成介面,以後只要每增加一個語言,只需實現介面即可,滿足了OCP原則,基本解決了方案一中存在的問題;

(2)如上代碼只是為了示範面向介面編程這個功能,並不完善,感興趣的讀者,可自行完善(如將語言定義為枚舉類型等);

方案二中的代碼,細心的讀者會發現,Main方法中new了三個對象,假若以後系統有300門語言,那豈不New 300個類,這樣的話,也不利於代碼維護呀,怎麼解決這個問題呢?(提示一下,採用設計模式抽象工廠即可解決該問題)

2.3 用委託實現

在這裡,沒接觸過委託的讀者,先跳過這部分,往下讀,看完(三)怎樣使用委託(How to use)後,再來看本部分。

 Code

 View Code

 Result

 2.3 分析上述三種實現方案的關係

通過上訴三種方式的比較,我們容易得出委託的如下結論:

(1)抽象方法,屏蔽方法細節,調用只需傳遞方法名字即可;

(2)能夠實現程式的解耦,松耦合(在方案一中,GetGreetingContens方法體內new了GreetToUsers對象,強耦合)

(3)委託一般扮演中間者的角色,這功能在委託事件中體現非常明顯(第二部分 事件 將詳細論述)

如我們在租房子時,可以直接找房東(技術實現的一般方法,強耦合,讓租房者和房東直接聯絡),也可找中介(技術實現的委託,松耦合,租房者通過中介來與房東聯絡)

 

2.4 委託背景概述

委託的重要產生背景,就是事件驅動模型(關於什麼是事件和事件驅動,在本文第二部份 事件 論述)。

(二) 委託定義

 用delegate關鍵字定義委託(注意,委託是沒有方法體的,類似介面裡面的方法),在定義委託前,必須明確兩個問題:

1.委託將要綁定的方法;

2.委託的形參類型,形參個數和委託的傳回值必須與將要綁定的方法的形參類型,形參個數和傳回值一致;

(三)相關概念

委託涉及的相關概念有函數指標,型別安全、事件、Lambda運算式等

1.函數指標:在C++中,指標的一個類別,主要指向函數(變數指標,主要指向變數地址),可以把C#中的委託理解為函數指標;

2.型別安全:在C++中,我們都知道指標是類型不安全的(傳回值,傳回型別和什麼時候返回,這些都是未知的),而委託是型別安全的;

3.事件:可以把事件理解為委託的一種特例(在本文第二部份 事件 論述)

4.Lambda運算式:委託與Lambd運算式相結合,實現高效編程,與Jquery的“較少代碼做更多的事”類似,委託與Lambda,Linq相結合,使較短代碼就能實現比較複雜的功能(在本篇文章中不講解Lambda與Lambda樹,將在後續文章中講解)

(四)委託組成

大致分為兩部分:聲明委託和註冊方法(也叫Binder 方法)

1.聲明委託

用delegate聲明;

2.Binder 方法

綁定具體方法,傳遞方法名稱;

(五) 委託種類

委託種類,一般分為多播委託和單播委託

1.單播委託:綁定單個方法

2.綁定多個方法

(六) 委託操作

1.Binder 方法

2.解除綁定方法

二  委託能解決什麼問題(Can do)

1.避免核心方法中存在大量的if....else....語句(或swich開關語句);

2.滿足程式設計的OCP原則;

3.使程式具有擴充性;

4.綁定事件;

5.結合Lambda運算式,簡化代碼,高效編程;

6.實現程式的松耦合(解耦),這個在事件(event)中體現比較明顯;

三  怎麼使用委託(How to use)(本篇文章不談匿名委託,匿名委託具體內容,將在Lambda章節講解)

(一)委託的基本構成

通常地,使用委託的步驟與使用類的步驟是一樣的。大致分為兩步:定義委託和Binder 方法(傳遞方法)

1.定義委託

用delegate關鍵字定義委託(注意,委託是沒有方法體的,類似介面裡面的方法),在定義委託前,必須明確兩個問題:

(1).委託將要綁定的方法;

(2).委託的形參類型,形參個數和委託的傳回值必須與將要綁定的方法的形參類型,形參個數和傳回值一致;

public delegate  委託傳回型別  委託名(形參)

例子:如上我們委託將要表示系統輸出的問候語

a.委託將要綁定的方法

 public string ChinesePeople(string UserName)        {            string GreetContents = "您好!" + UserName;            return GreetContents;        }        //English People        public string EnglishPeople(string UserName)        {            string GreetContents = "Hello," + UserName + "!";            return GreetContents;        }        //非英非漢        public string OtherPeople(string UserName)        {            return "Sorrry,當前系統只支援漢語與英語";        }

b.由如上方法可看出,方法的傳回型別為string,方法有一個string類型的形參,在定義委託時,與其保持一致即可

//定義委託public delegate string DelegateGetGreeting(string UserName);

2.Binder 方法

使用委託時,將方法名字作為參數傳遞給委託即可

1 GreetToUsers greetToUsers = new GreetToUsers();2 GetGreetingContents(UserName, greetToUsers.ChinesePeople)

(二)委託Binder 方法

1.綁定單個方法

綁定單個方法,將單個方法名字傳給委託即可

 View Code

另一種不太規範寫法:不用GetGreetingContents(string UserName,DelegateGetGreeting delegateGetGreeting)方法

 View Code

之所以不規範,主要是在項目中,不利於代碼的模組化。

2.綁定多個方法(多播委託)

注意:綁定多個方法時,委託範圍類型必須為void類型,否則只返回最後一個綁定的值。

 綁定多個方法,採用 += 綁定

 View Code

3.解除綁定方法

解載綁定的方法,採用 -= 解除綁定

 View Code

(三)委託機制

 將如下代碼通過反組譯碼工具.NET Reflector反組譯碼

 View Code

反組譯碼

 分析:

1.三個核心方法:BeginInvoke,EndInvoke和Invoke

(1)使用Invoke完成一個委託方法的封送,就類似於使用SendMessage方法來給介面線程發送訊息,是一個同步方法。也就是說在Invoke封送的方法被執行完畢前,Invoke方法不會返回,從而調用者線程將被阻塞。

(2使用BeginInvoke方法封送一個委託方法,類似於使用PostMessage進行通訊,這是一個非同步方法呼叫。也就是該方法封送完畢後馬上返回,不會等待委託方法的執行結束,調用者線程將不會被阻塞。但是調用者也

可以使用EndInvoke方法或者其它類似WaitHandle機制等待非同步作業的完成。

總結:但是在內部實現上,Invoke和BeginInvoke都是用了PostMessage方法,從而避免了SendMessage帶來的問題。而Invoke方法的同步阻塞是靠WaitHandle機制來完成的。

提示:

最近瀏覽一篇文章,也講得不錯:http://blog.csdn.net/goodshot/article/details/6157529

要想深入瞭解,請參照《CLR Via C#》,

第二部分  事件

關於事件(event),將會從如下四個角度來分析.

1.什麼是事件

2.事件能解決什麼問題

3.怎麼使用事件

4.事件機制

 

一  什麼是事件

 談到委託,必提事件,事件本質是對委託的封裝,對外提供add_EventName(對應+=)和remove_EventName(對應-=)訪問,從而實作類別的封裝性。

1.種類

強型別事件和弱類型事件

2.一些用處

(1)WebForm控制項的Click事件。做過WebForm開發的朋友,可能對事件是非常熟悉的,如拖一個Button,雙擊,就自動在後台產生Button的Click事件,如所示。

原理:在Windows運用程式中,Button類提供了Click事件,其本質就是委託,當我們觸發Click事件時,調用的處理常式方法需要參數,其參數就是由委託類型來定義的。

(2)設計模式發布/訂閱。事件是基於委託的,為委託提供了一種發布/訂閱機制。

二 事件能解決哪些問題

1.將公有的委託變數定義為私人變數,從而滿足類的封裝性原則;

2.具有委託具有的作用;

三 如何使用事件

1.聲明委託

public delegate void DelegateGetGreeting(string UserName);

2.聲明事件

與委託聲明一樣,只不過多了一個關鍵字event

public event DelegateGetGreeting EventGreet;

3.時間註冊方法

事件註冊方法與委託註冊方法是一樣的。

1 DelegateGreet DG= new DelegateGreet();2 //DG.delegateGetGreeting = GTU.ChinesePeople;//註冊方法3 DG.EventGreet+= GTU.ChinesePeople;4 DG.EventGreet += GTU.EnglishPeople;

4.呼叫事件

調用定義事件的方法

DG.GreetUser("小王");

完整代碼如下:

 View Code

四 事件機制

 事件的本質就是委託,向外提供兩個存取方法add_EventName(對應+=)和remove-EventName(對應-=),我們通過.NET Reflector反組譯碼工具來查看,到底是不是這樣的。

 

參考文獻

【01】C#進階編程(第七版)  (Christian Nagel,Bill Evjen和Jay Glynn 編著,李銘 譯,黃靜 審校) 

【C#系列】你應該知道的委託和事件

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.