步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制.docx_第1頁
步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制.docx_第2頁
步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制.docx_第3頁
步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制.docx_第4頁
步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制.docx_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

步步為營(yíng) C# 技術(shù)漫談 五、事件與委托機(jī)制 概述 C#中的委托類似于C或C+中的函數(shù)指針。使用委托使程序員可以將方法引用封裝在委托對(duì)象內(nèi)。然后可以將該委托對(duì)象傳遞給可調(diào)用所引用方法的代碼,而不必在編譯時(shí)知道將調(diào)用哪個(gè)方法。與C或C+中的函數(shù)指針不同,委托是面向?qū)ο?,而且是類型安全的?C#中的“事件”是當(dāng)對(duì)象發(fā)生某些事情時(shí),類向該類的客戶提供通知的一種方法。事件最常見的用途是用于圖形用戶界面;通常,表示界面中的控件的類具有一些事件,當(dāng)用戶對(duì)控件進(jìn)行某些操作(如單擊某個(gè)按鈕)時(shí),將通知這些事件。使用委托來聲明事件。委托對(duì)象封裝一個(gè)方法,以便可以匿名調(diào)用該方法。事件是類允許客戶為其提供方法(事件發(fā)生時(shí)應(yīng)調(diào)用這些方法)的委托的一種方法。事件發(fā)生時(shí),將調(diào)用其客戶提供給它的委托。 注明:委托是對(duì)方法的包裝 在不確定要調(diào)用什么方法時(shí)候而又不能用抽象或者多態(tài)實(shí)現(xiàn)的時(shí)候用委托。 委托在Observer模式示例:先創(chuàng)建PilotLamp.cs:?12345678910111213141516public interface PilotLamp / / green light / void TurnOn(); / / notice / string Notice get; set; 再創(chuàng)建DelegateEvent.cs:?1public delegate void EventHandler();再創(chuàng)建TrafficLight.cs:?123456789101112131415161718192021222324252627public class TrafficLight : PilotLamp public event EventHandler Notices; private string notice; #region GreenLight 成員 public void TurnOn() if (Notices != null) Notices(); public string Notice get return notice; set notice = value; #endregion 再創(chuàng)建Driver.cs:?12345678910111213141516public class Driver private string Name; private PilotLamp greenLight; public Driver(string name, PilotLamp greenLight) this.Name = name; this.greenLight = greenLight; public void GoLeft() Console.WriteLine(string.Format(1司機(jī),0,請(qǐng)向左開車., greenLight.Notice, Name); 再創(chuàng)建Pedestrian.cs:?1234567891011121314public class Pedestrian private string Name; private PilotLamp greenLight; public Pedestrian(string name, PilotLamp greenLight) this.Name = name; this.greenLight = greenLight; public void GoThrough() Console.WriteLine( string.Format(0同志,1,請(qǐng)向前走., Name, greenLight.Notice); 最后再調(diào)用:?1234567891011121314151617181920212223242526272829303132public partial class Run : Form public Run() InitializeComponent(); private void btnRun_Click(object sender, EventArgs e) /- TrafficLight trafficLight = new TrafficLight(); Driver driverOne = new Driver(張三, trafficLight); Driver driverTwo = new Driver(李四, trafficLight); Pedestrian pedestrianOne = new Pedestrian(王五, trafficLight); Pedestrian pedestrianTwo = new Pedestrian(麻六, trafficLight); trafficLight.Notices += new Observer.EventHandler(driverOne.GoLeft); trafficLight.Notices += new Observer.EventHandler(driverTwo.GoLeft); trafficLight.Notices += new Observer.EventHandler(pedestrianOne.GoThrough); trafficLight.Notices += new Observer.EventHandler(pedestrianTwo.GoThrough); trafficLight.Notice = 綠燈亮了.; trafficLight.TurnOn(); /- 輸出時(shí)選控制臺(tái)應(yīng)用程序如圖:結(jié)果如下圖:事件的使用示例:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263namespace DelegateAndEvent class Program static void Main(string args) Publishser pub = new Publishser(); OneScriber oneSub = new OneScriber(); TwoScriber twoSub = new TwoScriber(); ThreeScriber threeSub = new ThreeScriber (); pub.NumberChanged += new GeneralEventHandler(oneSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(twoSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(threeSub.OnNumberChanged); pub.DoSomething(); public delegate string GeneralEventHandler(); public class Publishser public event GeneralEventHandler NumberChanged; public void DoSomething() if (NumberChanged != null) Delegate generalEventHandlers = NumberChanged.GetInvocationList(); foreach (Delegate generalEventHandler in generalEventHandlers) GeneralEventHandler mothed = (GeneralEventHandler)generalEventHandler; string rtn = mothed(); Console.WriteLine(rtn); System.Threading.Thread.Sleep(2000); public class OneScriber public string OnNumberChanged() return One Subscriber; public class TwoScriber public string OnNumberChanged() return Two Subscriber; public class ThreeScriber public string OnNumberChanged() return Three Subscriber; 運(yùn)行結(jié)果:注意到Delegate是GeneralEventHandler 的基類,所以為了觸發(fā)事件,先要進(jìn)行一個(gè)向下的強(qiáng)制轉(zhuǎn)換,之后才能在其上觸發(fā)事件,調(diào)用所有注冊(cè)對(duì)象的方法。除了使用這種方式以外,還有一種更靈活方式可以調(diào)用方法,它是定義在Delegate基類中的DynamicInvoke()方法:public object DynamicInvoke(params object args);這可能是調(diào)用委托最通用的方法了,適用于所有類型的委托。它接受的參數(shù)為object,也就是說它可以將任意數(shù)量的任意類型作為參數(shù),并返回單個(gè)object對(duì)象。上面的DoSomething()方法也可以改寫成下面這種通用形式:代碼作如下改動(dòng):?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768namespace DelegateAndEvent class Program static void Main(string args) Publishser pub = new Publishser(); OneScriber oneSub = new OneScriber(); TwoScriber twoSub = new TwoScriber(); ThreeScriber threeSub = new ThreeScriber(); pub.NumberChanged += new GeneralEventHandler(oneSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(twoSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(threeSub.OnNumberChanged); List strlist = pub.DoSomething(); foreach (string result in strlist) Console.WriteLine(result); System.Threading.Thread.Sleep(5000); public delegate string GeneralEventHandler(); public class Publishser public event GeneralEventHandler NumberChanged; public List DoSomething() List strList = new List(); if (NumberChanged = null) return strList; Delegate generalEventHandlers = NumberChanged.GetInvocationList(); foreach (Delegate generalEventHandler in generalEventHandlers) / GeneralEventHandler mothed = (GeneralEventHandler)generalEventHandler; string rtn = generalEventHandler.DynamicInvoke(null).ToString(); strList.Add(rtn); return strList; public class OneScriber public string OnNumberChanged() return One Subscriber; public class TwoScriber public string OnNumberChanged() return Two Subscriber; public class ThreeScriber public string OnNumberChanged() return Three Subscriber; 結(jié)果如下:還是一樣的結(jié)果.委托的定義會(huì)生成繼承自MulticastDelegate的完整的類,其中包含Invoke()、BeginInvoke()和EndInvoke()方法。當(dāng)我們直接調(diào)用委托時(shí),實(shí)際上是調(diào)用了Invoke()方法,它會(huì)中斷調(diào)用它的客戶端,然后在客戶端線程上執(zhí)行所有訂閱者的方法(客戶端無法繼續(xù)執(zhí)行后面代碼),最后將控制權(quán)返回客戶端。注意到BeginInvoke()、EndInvoke()方法,在.Net中,異步執(zhí)行的方法通常都會(huì)配對(duì)出現(xiàn),并且以Begin和End作為方法的開頭(最常見的可能就是Stream類的BeginRead()和EndRead()方法了)。它們用于方法的異步執(zhí)行,即是在調(diào)用BeginInvoke()之后,客戶端從線程池中抓取一個(gè)閑置線程,然后交由這個(gè)線程去執(zhí)行訂閱者的方法,而客戶端線程則可以繼續(xù)執(zhí)行下面的代碼。BeginInvoke()接受“動(dòng)態(tài)”的參數(shù)個(gè)數(shù)和類型,為什么說“動(dòng)態(tài)”的呢?因?yàn)樗膮?shù)是在編譯時(shí)根據(jù)委托的定義動(dòng)態(tài)生成的,其中前面參數(shù)的個(gè)數(shù)和類型與委托定義中接受的參數(shù)個(gè)數(shù)和類型相同,最后兩個(gè)參數(shù)分別是AsyncCallback和Object類型,對(duì)于它們更具體的內(nèi)容,可以參見下一節(jié)委托和方法的異步調(diào)用部分?,F(xiàn)在,我們僅需要對(duì)這兩個(gè)參數(shù)傳入null就可以了。另外還需要注意幾點(diǎn): 在委托類型上調(diào)用BeginInvoke()時(shí),此委托對(duì)象只能包含一個(gè)目標(biāo)方法,所以對(duì)于多個(gè)訂閱者注冊(cè)的情況,必須使用GetInvocationList()獲得所有委托對(duì)象,然后遍歷它們,分別在其上調(diào)用BeginInvoke()方法。如果直接在委托上調(diào)用BeginInvoke(),會(huì)拋出異常,提示“委托只能包含一個(gè)目標(biāo)方法”。 如果訂閱者的方法拋出異常,.NET會(huì)捕捉到它,但是只有在調(diào)用EndInvoke()的時(shí)候,才會(huì)將異常重新拋出。而在本例中,我們不使用EndInvoke()(因?yàn)槲覀儾魂P(guān)心訂閱者的執(zhí)行情況),所以我們無需處理異常,因?yàn)榧词箳伋霎惓?,也是在另一個(gè)線程上,不會(huì)影響到客戶端線程(客戶端甚至不知道訂閱者發(fā)生了異常,這有時(shí)是好事有時(shí)是壞事)。 BeginInvoke()方法屬于委托定義所生成的類,它既不屬于MulticastDelegate也不屬于Delegate基類, 我們需要進(jìn)行一個(gè)向下轉(zhuǎn)換,來獲取到實(shí)際的委托類型。示例:?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869namespace DelegateAndEvent class Program static void Main(string args) Publishser pub = new Publishser(); OneScriber oneSub = new OneScriber(); TwoScriber twoSub = new TwoScriber(); ThreeScriber threeSub = new ThreeScriber(); pub.NumberChanged += new GeneralEventHandler(oneSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(twoSub.OnNumberChanged); pub.NumberChanged += new GeneralEventHandler(threeSub.OnNumberChanged); List strlist = pub.DoSomething(); foreach (string result in strlist) Console.WriteLine(result); System.Threading.Thread.Sleep(5000); public delegate string GeneralEventHandler(object sender,EventArgs e); public class Publishser public event GeneralEventHandler NumberChanged; public List DoSomething() List strList = new List(); if (NumberChanged = null) return strList; Delegate generalEventHandlers = NumberChanged.GetInvocationList

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論