溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

c#中的委托與事件是什么

發(fā)布時(shí)間:2021-08-25 17:37:42 來(lái)源:億速云 閱讀:206 作者:chen 欄目:編程語(yǔ)言

這篇文章主要介紹“c#中的委托與事件是什么”,在日常操作中,相信很多人在c#中的委托與事件是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”c#中的委托與事件是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

一、什么是委托呢?

聽(tīng)著名字挺抽象,確實(shí)不好理解。面試官最喜歡考察這個(gè),而且更喜歡問(wèn):“委托和事件有何異同?”。如果對(duì)一些知識(shí)點(diǎn)沒(méi)有想明白,那么很容易被繞進(jìn)去。研究任何事物,我們不妨從它的定義開(kāi)始,委托也不例外。那么先來(lái)看c#中的委托定義,先來(lái)個(gè)例子:

public delegate void GetPacage(string code);

這個(gè)委托,看起來(lái)就是個(gè)方法簽名,取包裹,需要驗(yàn)證碼。與方法簽名不同的地方,在于多了一個(gè)delegate。c#中不乏一些便利好用的語(yǔ)法,比如foreach、yield,每一個(gè)關(guān)鍵字背后都有一段故事。delegate的背后,又有什么故事呢?其實(shí)就是c#編譯器幫我們做了些什么事情。要知道這個(gè),我們得看生成的IL,如何查看IL?請(qǐng)看下圖:

vs命令行中輸入 ildasm,會(huì)打開(kāi)一個(gè)反編譯的窗口,選擇我們的程序集,如下圖:

從圖中可以看出:

1、委托的本質(zhì)就是一個(gè)密封類(lèi),這個(gè)類(lèi)繼承了MulticastDelegate(多播委托)

2、委托的構(gòu)造函數(shù),有兩個(gè)參數(shù),一個(gè)類(lèi)型是IntPtr,用來(lái)接收方法的,如下圖:

3、可以同步調(diào)用(Invoke),也可以異步調(diào)用 (BeginInvoke、EndInvoke)

注:

1、多播委托:一個(gè)委托可以代表多個(gè)相同簽名的方法,當(dāng)委托被調(diào)用時(shí),這些方法會(huì)依次執(zhí)行

2、IntPtr表示窗口的時(shí)候,叫它“句柄”,表示方法時(shí),叫它“指針”

3、異步調(diào)用:會(huì)產(chǎn)生一個(gè)線(xiàn)程,異步執(zhí)行

二、委托有什么用?

在js中,并沒(méi)有提委托的概念,卻有“回調(diào)”,比如ajax回調(diào)。把一個(gè)函數(shù)傳遞到另外一個(gè)函數(shù)里執(zhí)行,是非常自然的事情。但是在c#中,不能直接把方法名傳遞進(jìn)去。所以創(chuàng)造了委托這么個(gè)類(lèi)型。c#中的委托也是為了回調(diào)。委托有什么好處?舉個(gè)例子:皇帝頒發(fā)圣旨,得派一個(gè)大臣去。大臣到了目的地,宣讀圣旨后,這才得以執(zhí)行。這說(shuō)明以下兩點(diǎn):

1、委托有很好的封裝性

2、委托的實(shí)例化與它的執(zhí)行是在不同的對(duì)象中完成的

三、委托與代理

我說(shuō)的代理,是指設(shè)計(jì)模式中的代理。代理與實(shí)際對(duì)象有相同的接口,委托與實(shí)際方法有相同的方法簽名。這就是它們類(lèi)似的地方。無(wú)論是相同的接口,還是相同的方法簽名,其本質(zhì)是遵循相同的協(xié)議。這是它們僅存的相似點(diǎn)。不同點(diǎn)多了,如目的不同,委托只是回調(diào),而代理是對(duì)實(shí)際對(duì)象的訪(fǎng)問(wèn)控制。

四、委托和事件

先看一段代碼:

public delegate void GetPacage(string code); public class Heater {  public event EventHandler OnBoiled;  public event GetPacage PackageHandler;  private void RasieBoiledEvent()  {   if (OnBoiled == null)   {    Console.WriteLine("加熱完成處理訂閱事件為空");   }   else   {    OnBoiled(this, new EventArgs());   }  }  public void Begin()  {   heatTime = 5;   Heat();   Console.WriteLine("加熱器已經(jīng)開(kāi)啟", heatTime);  }  private int heatTime;  private void Heat()  {   Console.WriteLine("當(dāng)前Heat Method線(xiàn)程:" + Thread.CurrentThread.ManagedThreadId);   while (true)   {    Console.WriteLine("加熱還需{0}秒", heatTime);    if (heatTime == 0)    {     RasieBoiledEvent();     return;    }    heatTime--;    Thread.Sleep(1000);   }  } }

這個(gè)是加熱器例子,為了研究事件,里面混合了自定義的委托和事件。我們看看第6行編譯后的代碼(紅框):

編譯器幫我們做了如下的事情:

1、生成了一個(gè)私有的委托字段

[CompilerGenerated, DebuggerBrowsable(DebuggerBrowsableState.Never)]private GetPacage PackageHandler;

2、生成了添加和移除委托的方法

[CompilerGenerated]public void add_PackageHandler(GetPacage value){ GetPacage pacage2; GetPacage packageHandler = this.PackageHandler; do {  pacage2 = packageHandler;  GetPacage pacage3 = (GetPacage) Delegate.Combine(pacage2, value);  packageHandler = Interlocked.CompareExchange<GetPacage>(ref this.PackageHandler, pacage3, pacage2); } while (packageHandler != pacage2);}

這就是事件和委托的關(guān)系。有點(diǎn)像字段和屬性的關(guān)系。那有人說(shuō),事件是一種包裝的委托,或者特殊的委托,那么到底對(duì)不對(duì)呢?我覺(jué)得不對(duì)。比如我坐了公交車(chē)回家了,能說(shuō)我是一個(gè)特殊的公交車(chē)嗎?不能說(shuō)A事物擁有了B事物的能力,就說(shuō)A是特殊的B。那到底該怎么描述事件和委托之間的關(guān)系呢?事件基于委托,但并非委托??梢园咽录闯晌械拇怼T谑褂谜呖磥?lái),只有事件,而沒(méi)有委托。事件是對(duì)委托的包裝,這個(gè)沒(méi)錯(cuò),到底包裝了哪些東西?

1、保護(hù)委托字段,對(duì)外不開(kāi)放,所以外部對(duì)象沒(méi)法直接操作委托。提供了Add和Remove方法,供外部對(duì)象訂閱事件和取消事件

2、事件的處理方法在對(duì)象外部定義,而事件的執(zhí)行是在對(duì)象的內(nèi)部,至于事件的觸發(fā),何時(shí)何地?zé)o所謂。

五、c#鼠標(biāo)鍵盤(pán)事件

此類(lèi)事件的底層實(shí)現(xiàn),一方面是消息循環(huán),另一方面是硬件中斷,或者兩者結(jié)合實(shí)現(xiàn),有空了再研究。

六、經(jīng)典面試題,貓叫、老鼠跑了,主人醒來(lái)了

public delegate void ScreamHandler(); public class Cat {  public event ScreamHandler OnScream;  public void Scream()  {   Console.WriteLine("貓叫了一聲");   OnScream?.Invoke();  } } public class Mouse {  public Mouse(Cat c)  {   c.OnScream += () =>   {    Console.WriteLine("老鼠跑了");   };  } } public class People {  public People(Cat c)  {   c.OnScream += () =>   {    Console.WriteLine("主人醒來(lái)了");   };  } }

客戶(hù)端調(diào)用:

Cat cat = new Cat(); Mouse m = new Mouse(cat); People p = new People(cat); cat.Scream();

到此,關(guān)于“c#中的委托與事件是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI