国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

9、委托、事件、Lambda

2019-11-17 02:28:55
字體:
供稿:網(wǎng)友

9、委托、事件、Lambda

2015-03-30 16:57 by 七星端硯, ... 閱讀, ... 評論, 收藏, 編輯
關(guān)于委托,肯定是要有問題的。

第一個(gè)問題,委托用來干什么?

看.net中的表述:在.net平臺下,委托類型用來定義和相應(yīng)應(yīng)用程序中的回調(diào)。(回調(diào)?處理內(nèi)存中兩個(gè)實(shí)體雙向通信的一種技術(shù)。)

第二個(gè)問題,委托和C++(其實(shí)起源于C語言)函數(shù)指針?

必然要說區(qū)別,雖然委托和函數(shù)指針都是指向以后要調(diào)用的方法。但委托相比于函數(shù)指針來說,主要有兩點(diǎn)優(yōu)勢:一,委托是對象(我們知道,委托和類在一個(gè)層次)。二,委托是內(nèi)置支持多路廣播和異步方法調(diào)用的。
關(guān)于事件。

問題,事件用來干什么?

事件是為委托服務(wù)的,它使得我們處理委托類型的過程更簡化和高效。
關(guān)于Lambda。

問題,這東西又是干什么的?

Lambda使用操作符=>來讓我們調(diào)用委托,只不過更簡單。OK,看來,這都和委托密不可分,知道委托是個(gè)什么玩意,就能了解事件和Lambda是什么玩意了。

一、.net委托類型

之前的回調(diào)函數(shù),C中的函數(shù)指針,也就是一個(gè)指向內(nèi)存中一塊地址完事。我們不了解更多的有關(guān)類型的信息,比如什么類型,什么返回值,媽蛋,都一抹黑。委托出來了,覺得之前的那一套回調(diào)不安全,于是我變成類型安全的對象,指向程序中以后會被調(diào)用的方法(可以是多個(gè)。任性!)

1.委托能包含什么東西?有這些東西之后,有神馬好處?

它所調(diào)用的函數(shù)方法名稱;方法的參數(shù)(可選);方法的返回值(可選)。有這些,在運(yùn)行時(shí)我可以動(dòng)態(tài)調(diào)用指向的方法。由此一來,本委托就自動(dòng)有了同步或一部訪問方法的能力,也就不用Thread那一套來調(diào)用輔助方法了,算是簡化了編程工作。

2.委托干了什么,怎么干的?

定義:public delegate int BinaryOp(int x, int y);表示一個(gè)指向操作兩個(gè)整數(shù)返回一個(gè)整數(shù)的方法。當(dāng)編譯的時(shí)候,委托就會變成有三個(gè)公共方法的東東,三個(gè)方法:Invoke、BeginInvoke、EndInvoke方法,第一個(gè)用來同步調(diào)用的,后兩個(gè)異步調(diào)用。而異步調(diào)用一般用來調(diào)用比較耗時(shí)的方法。(我們寫界面的時(shí)候,經(jīng)常會用到,防止界面卡逼,就異步調(diào)用,不影響界面的移動(dòng)和其他的操作。)在內(nèi)存中她們的表示經(jīng)常如下(其中下劃線為紅線的可以寫成返回類型和參數(shù)類型(不論個(gè)數(shù))):由上面的那個(gè)偽代碼就能看得出來,委托其實(shí)是和類在一個(gè)層次的東西,它還有基類,兩個(gè)基類:System.MulticastDelegate和System.Delegate基類。簡單的委托實(shí)例(兩個(gè)數(shù)的加法):怎么干?委托在底層,實(shí)際上在MulticastDelegate派生類上調(diào)用了編譯器生成的invoke方法。說下委托的類型安全:如果試圖將一個(gè)不匹配的方法傳入委托,就會收到編譯錯(cuò)誤(例如上面的委托你傳入一個(gè)參數(shù)的方法。)

3.委托怎么發(fā)對象通知?

定義一個(gè)Car類,他的公共成員如下:定義委托,來判斷,當(dāng)加速的時(shí)候,會不會超過最大值而崩潰:下面是加速方法,當(dāng)速度不同的時(shí)候輸出一些不同的信息:PRogram的Main方法里面每次加速 二十,并且記錄每次加速之后的輸出:調(diào)用結(jié)果如下:由上,可以總結(jié)出委托通知的步驟:定義將通知發(fā)送給調(diào)用者的委托類型。聲明每個(gè)委托類型成員變量。在淚殤創(chuàng)建輔助函數(shù)使調(diào)用者能指定由委托成員變量保存的方法。修改方法,在適當(dāng)?shù)那樾蜗抡{(diào)用委托中的調(diào)用列表。

多路廣播是怎么回事?

意思就是說,一個(gè)委托對象可以維護(hù)一個(gè)可調(diào)用方法的列表,而不只是單獨(dú)的一個(gè)方法。how?就涉及到+=和-=操作符了。上面的委托調(diào)用方法再寫一個(gè):Car中的方法修改:調(diào)用代碼:結(jié)果:同理,如果是想要移除方法,用-=操作符就可以了。相當(dāng)于退訂功能。

4.方法組轉(zhuǎn)換語法

C#提供的方法組轉(zhuǎn)換的語法,方便了委托操作,允許我們在調(diào)用委托作為參數(shù)的方法時(shí)候直接提供方法的名稱,而不用創(chuàng)建委托對象。如,上面的創(chuàng)建委托對象的過程都可以省了,成為如下代碼:c1.RegistWithCarEngine(OnCarEngineEvent2);

5.委托協(xié)變

拿上面的那個(gè)Car舉例子來說,如果我們派生了一個(gè)NewCar的類,并創(chuàng)建一個(gè)委托類型,可以指向返回該類的方法。因?yàn)槲惺前踩愋停覀儾荒苡梅祷谻ar累的委托,必須再定義一個(gè)新委托。而委托協(xié)變,就是允許我們創(chuàng)建一個(gè)委托能指向返回類以及相關(guān)繼承體系的方法。我們可以將上面一個(gè)返回Car的委托結(jié)果,進(jìn)行強(qiáng)制轉(zhuǎn)換獲得。CarDelegate car = new carDelegate(new NewCar(xxx));用的時(shí)候,NewCar newCar = (NewCar)car;。

6.泛型委托

C#允許我們定義泛型委托類型,例如假設(shè)我們希望定義一個(gè)委托類型來調(diào)用任何返回void并且接受單個(gè)參數(shù)的方法。如果這個(gè)參數(shù)可能會不同,我們就可以通過類型參數(shù)來構(gòu)建。泛型委托提供了更靈活的方式來指定類型安全的形式進(jìn)行調(diào)用的方法。之前,我們一般通過使用System.Object參數(shù)來達(dá)到相似的目的:public delegate void MyDelegate(object arg);盡管如此,但是我們會因此失去類型安全并且可能還會有裝箱損失。

二、C#事件

使用委托會遇到的問題。(破壞封裝性)我們沒把委托定義為私有的情況下,調(diào)用者就可以直接訪問委托對象,這樣,調(diào)用者還可以重新把變量賦值給新的委托對象。Ooops!這下問題就出現(xiàn)了。之前的方法相當(dāng)于刪了,并且調(diào)用者還可以直接調(diào)用委托的調(diào)用列表。一句話說:公共成員打破了封裝,不僅會導(dǎo)致代碼難以維護(hù)和調(diào)試,還會導(dǎo)致應(yīng)用程序的安全風(fēng)險(xiǎn)。

1.事件是干毛的?怎么干?

上面說了問題,事件就出來了,就可以知道,事件就是干這玩意的。(包裝委托,使其不破壞封裝性)。怎么實(shí)現(xiàn)的呢?在編譯器處理event關(guān)鍵字的時(shí)候,它會自動(dòng)提供注冊和注銷方法以及任何必要的委托類型成員變量(貌似還簡化了委托),并且這些委托成員變量總是私有的,因此不可能從觸發(fā)事件的對象訪問它們(ooh,安全了)。事件的用法:下面是修改之后的加速方法:

2.那么事件是如何封裝委托的?(除了默認(rèn)將委托置為private,還有下面的封裝)

add_和remove_前綴。比如上面的AboutToBlow事件,在CIL代碼中封裝如下:由此可以看來,事件只是節(jié)省了鍵入事件,下面說說如何在調(diào)用者這邊監(jiān)聽傳入的事件。C#事件也簡化了注冊調(diào)用者事件處理程序的操作。現(xiàn)在無需指定自定義輔助方法,調(diào)用者僅需使用+=和-=操作符即可(操作符將在后臺觸發(fā)正確的add_xxx()方法或remove_xxx()方法)。使用C#的事件注冊語法修改Main方法如下:當(dāng)然,我們也可以用方法組轉(zhuǎn)換語法。就不再陳述。

3.創(chuàng)建自定義的事件參數(shù)。

微軟推薦的事件模式是什么樣子的呢?查看基礎(chǔ)類庫中某個(gè)類型發(fā)送的事件時(shí),會發(fā)現(xiàn)底層委托的第一個(gè)參數(shù)是一個(gè)System.Object,第二個(gè)參數(shù)是一個(gè)派生自System.EventArgs的子類型。System.EventArgs基類,表示一個(gè)不發(fā)送任何自定義信息的事件:所以,如果我們?nèi)绻獋鬟f自定義數(shù)據(jù),那么就需要?jiǎng)?chuàng)建一個(gè)派生自EventArgs的類。如下:我們修改委托,增添一個(gè)CarEventArgs參數(shù),就可以傳遞數(shù)據(jù)了。(事件不變。)public delegate void CarEngineHandler(object sender, CarEventArgs args);//定義委托調(diào)用方法: if (Exploded != null) { Exploded(this,new CarEventArgs("Sorry, this car is dead...")); }如何接受者想與發(fā)送事件的對象交互,我們可以現(xiàn)實(shí)強(qiáng)制轉(zhuǎn)換System.Object。這樣就可以使用傳遞給事件通過對象中的任何公共成員。

三、C#匿名方法

匿名方法又是干毛的?這可真是一波一波的,先是委托解決了函數(shù)指針的不安全性,但是后來嫌麻煩,又出現(xiàn)了事件。結(jié)果,事件也看起來啰里啰嗦,好吧,匿名方法登場:上面的注冊事件處理程序,被改成了: c1.AboutToBlow += delegate (object sender,CarEventArgs e) { Console.WriteLine("Eek! Going to fast!"); };看起來似乎是處理和注冊聲明到一塊兒了。說明:匿名方法中最后一個(gè)大括號必須以分好結(jié)束,否則,將產(chǎn)生一個(gè)編譯錯(cuò)誤。下面是匿名方法的語法的偽代碼:匿名方法非常有趣,它使我們能訪問定義他們的方法的本地變量。這些變量成為匿名方法的外部變量。有關(guān)匿名方法和定義方法的作用域之間的交互,有幾個(gè)重要的知識點(diǎn):匿名方法不能訪問定義方法中的ref或out參數(shù)。匿名方法中的本地變量不能與外部方法中的本地變量重名。匿名方法可以訪問外部類作用域中的實(shí)例變量(或靜態(tài)變量)。

四、Lambda表達(dá)式

Lambda表達(dá)式是干毛用的?好吧,徹底被干敗了,覺得匿名方法還麻煩,都把褲子脫了還嫌麻煩,于是就讓你比脫了褲子還簡單,看我Lambda的吧:編寫:Lambda表達(dá)式是這樣編寫的,首先,定義一個(gè)參數(shù)列表,“=>”標(biāo)記緊隨其后,然后就是處理這些參數(shù)的語句。下面表達(dá)式可以說明:ArgumentsToProcess=>StatementsToProcessThem。那么用Lambda表達(dá)式,如何表達(dá)上面的注冊處理程序?如下:c1.AboutToBlow +=(sender,e)=>{Console.WriteLine("Eek! Going to fast!");//在里面可以處理傳入的參數(shù)};

五、小結(jié)

這主要討論了四個(gè)東西,其實(shí)就是一個(gè),那就是委托,然后優(yōu)化成事件。然后簡化成匿名方法,最后簡化成Lambda表達(dá)式的過程。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 荔浦县| 文山县| 南召县| 白沙| 阿城市| 汝阳县| 清徐县| 兴义市| 星座| 勃利县| 天门市| 株洲县| 仁怀市| 丰都县| 洛扎县| 石楼县| 马关县| 曲周县| 永靖县| 博爱县| 大城县| 达州市| 藁城市| 邵东县| 乌兰县| 涡阳县| 城口县| 新竹县| 中阳县| 宝丰县| 扎鲁特旗| 梁河县| 平泉县| 海林市| 佳木斯市| 宁城县| 东宁县| 鄂尔多斯市| 桂平市| 台江县| 察隅县|