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

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

Delegate背后的秘密

2019-11-17 02:29:52
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

Delegate背后的秘密

2015-03-25 10:22 by JasonShenW, ... 閱讀, ... 評(píng)論, 收藏, 編輯

表面上看來(lái)使用delegate是一件很簡(jiǎn)單的事。

用delegate關(guān)鍵字定義,使用老套的new創(chuàng)建一個(gè)instance ,使用熟悉的方法調(diào)用寫法調(diào)用,只不過不在是方法名,而是委托名。但是在這背后CLR為我們做了很多。當(dāng)我們 寫下下面這句話時(shí)public delegate void FeedBack(Int32 val);其實(shí)相當(dāng)于 大概下面的代碼(省略部分多線程相關(guān)代碼)pubic class FeedBack:MulticastDelegate{ public FeedBack(Object object , IntPtr methodPtr) { xxxx } public virtual void Invoke(int32 val);}首先delegate 就是一個(gè)class。這個(gè)class會(huì)自動(dòng)繼承MuticastDelegate .然后,這個(gè)class 的構(gòu)造函數(shù)就如上面所示,我們先看第二個(gè)參數(shù) methodPtr 可以理解為函數(shù)的指針,或者說(shuō)函數(shù)的地址。委托在真正運(yùn)行的時(shí)候,就要找到這個(gè)函數(shù)的地址,并運(yùn)行這個(gè)函數(shù)。對(duì),我們要先找到這個(gè)函數(shù)的地址,對(duì)于 static類型的函數(shù),地址是確定的,而對(duì)于實(shí)例函數(shù)而言,內(nèi)部的函數(shù)地址則是不定的,它需要先確定具體的某個(gè)實(shí)例, 這既是第一個(gè)參數(shù)的用途,具體實(shí)例的引用,對(duì)于static類型的函數(shù),就會(huì)默認(rèn)傳入一個(gè)null。其實(shí),在基類 MutiCastDelegate中,有三個(gè)重要的非公開屬性_target_methodPtr_invokationlist一二兩個(gè)屬性 剛好對(duì)應(yīng)我們構(gòu)造函數(shù)傳入的兩個(gè)參數(shù),第三個(gè)屬性和委托鏈有關(guān),默認(rèn)為null,我們先不討論。也就是說(shuō):delegate 其實(shí)只是個(gè)wrapper ,包裝著需要真正操作的對(duì)象 以及它的方法。也就是說(shuō)委托的構(gòu)造函數(shù) 完成了 和具體真實(shí)對(duì)象以及真實(shí)方法的對(duì)應(yīng),而調(diào)用則是另一個(gè)方法 Invoke(int32 val)。這個(gè)方法會(huì)觸發(fā)真實(shí)方法的調(diào)用。
關(guān)于委托鏈?zhǔn)?。。。我就不深究了,因?yàn)閷?shí)在比較懶。。可以理解為 一個(gè)delegate數(shù)組一次存放著這些委托,然后調(diào)用的時(shí)候,內(nèi)部通過foreach一個(gè)一個(gè)調(diào)用。。.也就造成了整個(gè)委托鏈中的方法都被調(diào)用的 “鏈?zhǔn)椒磻?yīng)”。因?yàn)閮?nèi)部實(shí)現(xiàn)也就是數(shù)組,所以 具體調(diào)用次序是確定的,而不是隨機(jī)的,根據(jù)的加入委托鏈中的順序會(huì)依次調(diào)用這些方法。如何拼成一個(gè)委托鏈,有兩種寫法在早期版本中 通過 Delegate.Combine 靜態(tài)方法來(lái)拼接鏈,(每次拼接要記得賦給原先的鏈)。就像現(xiàn)實(shí)生活中裝鏈條一樣,有兩個(gè)參數(shù),第一個(gè)參數(shù)是 已裝的部分鏈,第二個(gè)參數(shù)是待裝的。(鏈子的內(nèi)部是依靠數(shù)組實(shí)現(xiàn)的)第二種寫法,是C#為了更好的輔助delegate而 自動(dòng)對(duì)+= 和-=這兩個(gè)操作符提供了重載。也就是說(shuō)delegate實(shí)例之間可以簡(jiǎn)單的通過+=和-=來(lái)拼接。這無(wú)疑相當(dāng)大的簡(jiǎn)化了 委托鏈。(至于怎么重載的,因?yàn)閼?。。就不模擬了。)拼完委托鏈之后,只需要直接調(diào)用委托一樣調(diào)用委托鏈即可,委托內(nèi)部的算法會(huì)依次調(diào)用每個(gè)拼接的元素。但有一個(gè)缺憾就是,如果委托是帶有返回值的,那么只能返回最后一個(gè)委托執(zhí)行的返回值前面所有委托的返回值都會(huì)被丟棄。有什么辦法呢,如下。
委托鏈的高級(jí)調(diào)用如上所說(shuō),如果直接invoke委托鏈的話,那么只有鏈尾的返回值會(huì)輸出出來(lái),并且簡(jiǎn)單直接的鏈?zhǔn)秸{(diào)用還有巨大的隱患,如果其中的某個(gè)delegate拋出異常,那整個(gè)鏈都會(huì)卡住 。如果想要的每一個(gè)委托的返回值,就不能用上面的方法。
委托與泛型我們先定義一個(gè)委托public void FeedBack(Int32 value);然后我們又突然需要另一個(gè)委托。。o(╯□╰)opublic void FeedBack(string value)可以這樣來(lái)定義嗎? ,絕對(duì)不可以??!委托的本質(zhì)是class 所以你上面的做法只是重復(fù)定義了同名的類罷了。委托可以融入泛型來(lái)更加強(qiáng)大 ,看下面的完整實(shí)例
 public delegate void FeedBack <T>(T para);    public delegate void FeedBack<Tint,Tstr>(Tint para1,Tstr para2);    class 委托可以有泛型嗎    {        public static void Main(string[] args)        {                       FeedBack<Int32 > fb = new FeedBack<int >(FeedBackInt);            FeedBack<String > fb2 = new FeedBack<string >(FeedbackString);            FeedBack<int ,string > fb3 = new FeedBack<int , string >(FeedbackIntString);            fb.Invoke(2);            fb2.Invoke( "haha");            fb3.Invoke(60,"haha" );            Console.ReadKey();        }         public static void FeedBackInt(Int32 val)        {            Console.WriteLine(val);        }        public static void FeedbackString(String str)        {            Console.WriteLine(str);        }        public static void FeedbackIntString(int val,string str)        {            Console.WriteLine(val+":" +str);        }    }}

不知道看到這里,你心里會(huì)不會(huì)隱隱約約有一種想法。。。。那就是微軟所想到的:通過泛型可以把你編程幾乎會(huì)用到的所有可能的委托囊括?。。。∷麄兇_實(shí)這樣做了。。這就是FCL 擁有的自建委托。不帶返回值的統(tǒng)稱 Action 帶返回值的統(tǒng)稱 Func. 自帶委托如下,參數(shù)最多上限16個(gè)。再多的話,這個(gè)方法本身就很有問題了。以及微軟建議,在需要使用委托的時(shí)候就是用內(nèi)建的這些委托,而不要再去自己創(chuàng)建委托類型了。那我們就遵守這個(gè)慣例吧。當(dāng)然 也有可能這些泛型不符合你需要的委托。 比如你需要這個(gè)delegate void bar(ref int32 z); ,或者說(shuō)你的泛型委托需要一些約束。那就得自己定義委托了。。
最常見的delegate的用途應(yīng)該是webform中的事件處理機(jī)制。我們常常會(huì)見到這樣的寫法:button1.Click += button1_Click;void button1_Click(Object sender, EventArgs e) {// Do something, the button was clicked...}在學(xué)習(xí)的時(shí)候竟然很少有人對(duì)這種寫法感到詫異。。 這是C# 提供的語(yǔ)法糖。正常的寫法是button1.Click += new EventHandler(button1_Click);現(xiàn)在認(rèn)識(shí)么? 就是簡(jiǎn)單的拼接 delegate 鏈而已╮(╯_╰)╭。 上面的語(yǔ)法糖是委托里的第一種語(yǔ)法糖。在需要委托實(shí)例的地方 不再需要委托實(shí)例,直接提供委托要包含的的函數(shù)名即可。(events 是更安全的delegate .實(shí)際上是使用自建的EventHandler委托,然后,每次觸發(fā)不同控件的時(shí)候,會(huì)通過EventHandler(sender,e)) 這個(gè)委托來(lái)觸發(fā)實(shí)際的方法。ok 委托先到這里。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 珲春市| 宜昌市| 临朐县| 太原市| 南京市| 红河县| 康定县| 吉安县| 北京市| 静安区| 新龙县| 河北省| 济源市| 武定县| 普兰县| 奎屯市| 新和县| 绥德县| 革吉县| 清丰县| 平潭县| 藁城市| 鹤壁市| 宿州市| 通化县| 玉树县| 高密市| 绥滨县| 永善县| 海淀区| 鄂托克旗| 那曲县| 分宜县| 同德县| 江城| 中西区| 沙河市| 浏阳市| 长汀县| 横山县| 土默特左旗|