- Unity3D高級編程:主程手記
- 陸澤西
- 12字
- 2022-01-07 14:46:16
2.5 委托、事件、裝箱、拆箱
2.5.1 委托與事件
使用過C或C++的讀者對指針是什么應該很清楚,指針是一個需要謹慎對待的東西,它不僅可以指向變量的地址,還可以指向函數的地址,本質上,它是指向內存的地址。
在C#中萬物皆是類,我們使用C#的大部分時間里都沒有指針的身影,最多也只是引用,因為指針被封裝在內部函數中了。不過回調函數卻依然存在,于是C#多了一個委托(delegate)的概念,所有函數指針功能都以委托的方式來完成。委托可以視為一個更高級的函數指針,它不僅能把地址指向另一個函數,而且還能傳遞參數、獲得返回值等多個信息。系統還會為委托對象自動生成同步、異步的調用方式,開發人員使用BeginInvoke()、EndInvoke()方法就可以避開Thread類,從而直接使用多線程調用。
那么委托(delegate)在C#中是如何實現的呢?我們來一探究竟。
首先不要錯誤地認為委托是一個語言的基本類型,我們在創建委托時,其實就是創建一個delegate類實例,這個delegate委托類繼承了System.MulticastDelegate類,類實例里有BeginInvoke()、EndInvoke()、Invoke()這三個函數,分別表示異步開始調用、結束異步調用及直接調用。
但我們不能直接寫一個類來繼承System.MulticastDelegate類,因為它不允許被繼承,它的父類Delegate也同樣有這個規則,官方文檔中就是這么定的一個規則,相關表述翻譯后如下:
MulticastDelegate類是一個特殊的類,編譯器或其他工具可以從它這里繼承,但你不能直接繼承它。Delegate類也有同樣的規則。
Delegate類中有一個變量是用來存儲函數地址的,當變量操作=(等號)時,把函數地址賦值給變量保存起來。不過這個存儲函數地址的變量是一個可變數組,你可以認為它是一個鏈表,每次直接賦值時會換一個鏈表。
Delegate委托類還重寫了+=、-=這兩個操作符,其實就是對應MulticastDelegate類的Combine()和Remove()方法,當對函數進行+=和-=操作時,相當于把函數地址推入鏈表尾部,或者移出鏈表。
當委托被調用時,委托實例會把所有鏈表里的函數依次用傳進來的參數調用一遍。官方文檔中的表述翻譯后如下:
MulticastDelegate類中有一個已經連接好的delegate列表,被稱為調用列表,它由一個或者更多個元素組成。當一個multicast delegate被啟動調用時,所有在調用列表里的delegate都會按照它們出現的順序被調用。如果在執行列表期間遇到一個錯誤,就會立即拋出異常并停止調用。
看到這里我們徹底明白了,原來delegate關鍵字其實只是一個修飾用詞,背后是由C#編譯器來重寫的代碼,我們可以認為是編譯時把delegate這一句換成了Delegate,從而變成一個class,它繼承自System.MulticastDelegate類。
那么什么是event(事件),它和delegate又有什么關系?
event很簡單,它在委托(delegate)上又做了一次封裝,這次封裝的意義是,限制用戶直接操作delegate實例中變量的權限。
封裝后,用戶不能再直接用賦值(即使用=(等號)操作符)操作來改變委托變量,只能通過注冊或者注銷委托的方法來增減委托函數的數量。也就是說,被event聲明的委托不再提供“=”操作符,但仍然有“+=”和“-=”操作符可供操作。
為什么要限制呢?因為在平時的編程中,項目太過龐大,經手的人員數量太多,導致我們無法得知其他人編寫的代碼是什么,以及有什么意圖,這樣公開的delegate會直接暴露在外,隨時會被“=”賦值而清空前面累積起來的委托鏈表,委托的操作權限范圍太大,導致問題會比較嚴重。聲明event后,編譯器內部重新封裝了委托,讓暴露在外面的委托不再擔心有隨時被清空和重置的危險。因為經過event封裝后,不再提供賦值操作來清空前面的累加,只能一個個注冊或者一個個注銷委托(或者說函數地址),這樣就保證了“誰注冊就必須誰負責銷毀”的目的,更好地維護了delegate的秩序。
- Learning Neo4j
- Oracle從入門到精通(第3版)
- Visual C++程序設計學習筆記
- Interactive Data Visualization with Python
- Web Development with MongoDB and Node(Third Edition)
- Oracle數據庫編程經典300例
- 深入分析GCC
- C語言程序設計
- Java從入門到精通(視頻實戰版)
- Java多線程并發體系實戰(微課視頻版)
- 編程的原則:改善代碼質量的101個方法
- Python深度學習(第2版)
- Python繪圖指南:分形與數據可視化(全彩)
- Web前端開發精品課:HTML5 Canvas開發詳解
- Appcelerator Titanium Smartphone App Development Cookbook