看看這個常常被初級程式設計師弄不懂的 “事件”
眾所周知在面試中,經常有些崽子面試官會問些“事件和委託”的關係,也許一路走來的程式設計師大多都會被問到這個,那麼對於這個
高頻的”事件和委託“問題,如何回擊呢?首先我從最經典的一套面試題說起,用事件來實現 “貓爪老鼠“,這是一個從網上copy過來的一
個例子。
static void Main(string[] args) { Mouse mouse = new Mouse(); Cat cat = new Cat(); cat.OnCry(); Console.ReadLine(); } } public delegate void CryEventHandler(); public class Cat { public static event CryEventHandler Cry; public Cat() { Console.WriteLine("Cat:I'm coming."); } public virtual void OnCry() { Console.WriteLine("Cat:MiaoMiao"); if (Cry != null) { Cry.Invoke(); } } } public class Mouse { public Mouse() { Cat.Cry += new CryEventHandler(Run); Console.WriteLine("Mouse:I go to find something,and I must always listen cat's crying."); } public void Run() { Console.WriteLine("Mouse:A cat is coming,I must go back!"); } }
事件定義啥的什麼玩意這個我就不說了,沒什麼意思,為了瞭解這個跟委託有什麼關係,下面我們來看看這段程式碼最後生成的IL是什麼樣的。
1:CryEventHandler委託
1 public delegate void CryEventHandler();
這個我想大家都清楚,委託本質上是一個繼承於MulticastDelegate的類,同時會生成僅有的4個方法,看下IL即知。
2:Cat類
1 public class Cat 2 { 3 public static event CryEventHandler Cry; 4 5 public Cat() 6 { 7 Console.WriteLine("Cat:I'm coming."); 8 } 9 10 public virtual void OnCry()11 {12 Console.WriteLine("Cat:MiaoMiao");13 if (Cry != null)14 {15 Cry.Invoke();16 }17 }18 }
從這個類中,我們看到了一個Cry事件,然後就是一個Cry.Invoke(),不過當你看到Invoke的時候,你是不是很懷疑Cry是不是一個委託欄位呢?
其實你懷疑的是一點問題都沒有,32個贊,看下IL。
從上圖中我們看到了兩個好玩的東西:
① field Cry 欄位,完整定義如下,然來所謂的“事件欄位” 其實在IL下面蛻變成了委託欄位,如果你覺得很奇怪,請看第二點。
.field private static class Sample.CryEventHandler Cry
② add_Cry,remove_Cry,如果僅僅將事件欄位變成委託欄位,那確實是編譯器在發什麼神經,然來編譯器還給事件配備了兩個方法,這個
其實也就是事件裡面+=,-=的奧秘所在,下面我們挑add_Cry方法說下,看看方法定義的IL程式碼是怎麼樣的。
很新奇,我們找到了Combine方法,這個我們都知道,原來事件中的+=,其實就是利用Combine來將當前的委託例項放到Delegate的
委託連結串列中(其實裡面是array實現的),為了方便理解,我把上面的IL程式碼翻譯成C#程式碼。
1 public class Cat 2 { 3 ///4 /// 私有的委託變數 5 /// 6 private static CryEventHandler Cry; 7 8 ///9 /// 事件生成的方法10 /// 11 /// 12 public void Add_Cry(CryEventHandler cryEventHandler)13 {14 var result = (CryEventHandler)Delegate.Combine(Cry, cryEventHandler);15 16 Interlocked.CompareExchange(ref Cry, result, Cry);17 }18 19 public void Remove_Cry(CryEventHandler cryEventHandler)20 {21 var result = (CryEventHandler)Delegate.Remove(Cry, cryEventHandler);22 23 Interlocked.CompareExchange (ref Cry, result, Cry);24 }25 26 public Cat()27 {28 Console.WriteLine("Cat:I'm coming.");29 }30 31 public virtual void OnCry()32 {33 Console.WriteLine("Cat:MiaoMiao");34 35 if (Cry != null)36 {37 //委託專用的四個方法,invoke,begininvoke,endinvoke,ctor38 Cry.Invoke();39 }40 }41 }
可能有些同學對IL指令不是很熟悉,沒關係,我也一樣,我們部落格園上面有位大神飛鳥的一篇IL指令集的博文或許能幫得到你。
3:Mouse類
如果你對Cat類的IL程式碼琢磨的差不多的話,下面這個Mouse類就非常簡單了,僅僅呼叫而已嘛。
1 public class Mouse 2 { 3 public Mouse() 4 { 5 Cat.Cry += new CryEventHandler(Run); 6 Console.WriteLine("Mouse:I go to find something,and I must always listen cat's crying."); 7 } 8 9 public void Run()10 {11 Console.WriteLine("Mouse:A cat is coming,I must go back!");12 }13 }
這個地方最讓人關心的就是:Cat.Cry += new CryEventHandler(Run) 這個語句,從它的IL中可以看到其實做了三件事。
① ldftn: 將Run方法的非託管指標推送到計算堆疊上。
② newobj: 將CryEventHandler委託new一下,同時將計算堆疊上的Run方法的非託管指標作為建構函式的引數。
③ call: 呼叫Cat類的Add_Cry方法,將CryEventHandler的例項作為引數傳遞下去。
下面繼續將該IL程式碼反編譯回來,不過針對IL指令:call void Sample.Cat::add_Cry(class Sample.CryEventHandler)
並沒有很好的翻譯過來,只能new Cat()了一下才能呼叫Add_Cry,從而觸發了Cat的建構函式。
1 public class Mouse 2 { 3 public Mouse() 4 { 5 var cryHandler = new CryEventHandler(Run); 6 7 /* 8 * 針對IL:call void Sample.Cat::add_Cry(class Sample.CryEventHandler) 9 * 這個沒有反編譯好,因為我new Cat()將會再次呼叫建構函式。10 */11 new Cat().Add_Cry(cryHandler);12 13 Console.WriteLine("Mouse:I go to find something,and I must always listen cat's crying.");14 }15 16 public void Run()17 {18 Console.WriteLine("Mouse:A cat is coming,I must go back!");19 }20 }
好了,說了這麼多,應該也有總結性的東西出來了,原來事件是完完全全的建立在委託的基礎上,你可以認為事件就是用委託來玩一個
觀察者模式的,你甚至可以認為事件就是委託。沒有本質區別。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2806235/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 初級JAVA程式設計師的困惑Java程式設計師
- 看看你身邊的程式設計師有這8個習慣嗎程式設計師
- 如何從初級程式設計師變成高階程式設計師?程式設計師
- 招聘初級程式設計師必須考慮的6個因素程式設計師
- 幽默:不懂OO或DDD的程式設計師永遠無法get到這個幽默程式設計師
- 初級程式設計師的SQL拾遺-②(表操作)程式設計師SQL
- 超級搞笑,看看程式設計師、編輯狗、設計師 會雞的一天程式設計師
- 其實你不懂程式設計師程式設計師
- 誰說程式設計師不懂浪漫程式設計師
- 程式設計師的八個級別程式設計師
- 如何從初級程式設計師順利晉升到高階程式設計師?程式設計師
- 女程式設計師的無奈你不懂程式設計師
- 初級程式設計師考試大綱 (轉)程式設計師
- 我這個程式設計師 (轉)程式設計師
- 四個級別的 “自由” 程式設計師程式設計師
- 程式設計師的八個級別薦程式設計師
- 初級程式設計師需要知道的基本程式碼規範程式設計師
- 3月程式語言排行及程式設計師工資,快看看你在哪個等級!程式設計師
- 岑文初:做個簡單的程式設計師程式設計師
- 怎麼從初、中級Java程式設計師過渡到高階Java程式設計師?Java程式設計師
- 初級Java程式設計師提升自己的3條路線Java程式設計師
- 初級程式設計師的SQL拾遺(增刪改查)程式設計師SQL
- [轉載]初級Java程式設計師的學習路線Java程式設計師
- 初級程式設計師應該瞭解的Linux命令程式設計師Linux
- 看不懂自己寫的程式碼,這對一個職業程式設計師來說是不可饒恕的程式設計師
- Java進階之路——從初級程式設計師到架構師Java程式設計師架構
- 大師級的程式設計師,都在用這些工作法程式設計師
- 程式設計師的差距在哪裡?程式設計師的三個級別,你在哪裡?程式設計師
- 一個不懂營銷的程式設計師的一週營銷日記程式設計師
- 別把自己當個超人——給初級程式設計師的一點小小建議程式設計師
- 不懂產品的碼農不是好程式設計師程式設計師
- 請不要對程式設計師初學者說這些話……程式設計師
- 程式設計師世界常見的6個問題程式設計師
- 初級Java程式設計師所面臨的4大挑戰Java程式設計師
- 驚歎!這個盲人程式設計師是這樣寫程式碼的程式設計師
- 為什麼有些程式設計師不待見 PHP 這門語言?看看30萬程式設計師怎麼說!程式設計師PHP
- 關於程式設計師這個職業程式設計師
- 看看一個老程式設計師是如何手寫Spring MVC的!程式設計師SpringMVC