官术网_书友最值得收藏!

2.4 C#中的事件編程

人在某個環境某種風俗下生活,容易把這些環境和風俗看作是理所當然的。只有當一個人學習了一門外語后,他才能體會到母語的特點。同樣的道理,Java語言里事件編程的模式,在和其他語言里的事件編程對照后,才能顯示得更清晰。本節將看到常被用來和Java進行比較以及與之競爭的C#怎樣以不同的理念處理事件編程中遇到的問題。

2.4.1 代理

從之前的討論可以看出,事件編程的核心是發布者接收和運行以參數傳入的事件處理邏輯,而該邏輯最簡單和自然的載體就是一個回調函數。C和C++中的函數指針因為缺乏類型檢查而不安全,Java選擇放棄該功能。為了能傳遞方法又確保安全,Java 8用函數式接口把方法包裝起來。另一種思路則是直接以某種形式對方法進行類型檢查,C#(嚴格地說,是.NET編程框架)引入的代理(Delegate)就是以此為目的。代理是一種特殊的類型,用來設定單個方法的參數和返回類型,就像接口設定類的方法名稱和簽名。以它作為方法的類型,方法就能在通過編譯時檢查的前提下充當一級函數。隨著C#的演進,代理的聲明和初始化越來越簡潔和方便,并且成為C#中的匿名方法和Lambda表達式背后的類型,是用C#進行函數式編程的堅實基礎。下面的代碼樣例簡明地顯示了代理的演進。

Java和C#這兩門分別由大公司開發和維護的,都屬于C語言家族的,語法上有很多相似性的強類型語言,在相互競爭又彼此借鑒的演進過程中,陸續擁有很多對應的功能,比如函數式接口對代理、標記對元數據、雙方的對象容器框架、雙方的泛型方案,比較這些本質上相同的功能在兩種類似的語言中設計上的差異,是一件饒有興味的事情。

2.4.2 事件

代理有一個子類——多播代理(Multicast Delegate),能用+、-操作符將多個同類型的代理進行組合,當它被調用時,其成員會按照組合時的順序逐個被調用。可以看出,多播代理很適合用來保存事件的處理函數。C#又專門引入了event關鍵字來定義事件,event添加在一個多播代理類型之前,表示事件的處理函數必須符合該類型。收聽者可以向發布者公開的事件自由增刪符合條件的處理函數,而只有在發布者內部才能調用這些函數。與Java相同的是,C#中的事件信息對象仍然有專門的類型EventArgs,特定事件可以創建繼承自它的子類型。有了這些新發明的腳手架,C#中的事件編程可以直接將事件匹配到處理函數,發布者和收聽者的關系可以極為靈活,發布者的某個事件可以由任何對象中的函數處理,收聽者可以包含任何發布者的任意選定的事件的處理函數。因此C#從一開始就沒有用Java時遇到的問題,而且比函數式接口更接近函數式編程本質的代理,用于事件編程時也比前者更簡潔。演示這些概念最好的方法就是代碼樣例。

下面將2.3節中的鼠標事件的例子用C#改寫,以資比較。

主站蜘蛛池模板: 比如县| 香河县| 东城区| 印江| 岳普湖县| 电白县| 福州市| 大关县| 綦江县| 东宁县| 吉木乃县| 绥阳县| 永嘉县| 苍梧县| 通山县| 水富县| 嘉禾县| 台南市| 五大连池市| 三都| 汶上县| 米易县| 荥经县| 裕民县| 元氏县| 商丘市| 汕尾市| 灵台县| 临洮县| 深州市| 枣庄市| 高清| 辽宁省| 承德市| 沭阳县| 灯塔市| 烟台市| 原平市| 同德县| 瑞丽市| 商丘市|