最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解c# 委托鏈

 更新時間:2020年07月23日 10:02:28   作者:Learning hard  
這篇文章主要介紹了c# 委托鏈的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

引言:

上一專題介紹了下編譯器是如何來翻譯委托的,從中間語言的角度去看委托,希望可以幫助大家進(jìn)一步的理解委托,然而之前的介紹都是委托只是封裝一個方法,那委托能不能封裝多個方法呢?因為生活中經(jīng)常會聽到,我代表大家的意見等這樣的說話,既然委托也是一個代表,那他如果只能代表一個人,那他的魅力就不是很大了吧,所以我們就會委托能不能代表多個方法的? 答案是可以的,這就是本專題要講的內(nèi)容——委托鏈,委托鏈也是一個委托,只是因為它是把多個委托鏈在一起,所以我們就以委托鏈來這么稱呼它的。

一、到底什么是委托鏈

我們平常實(shí)例化委托對象時都是綁定一個方法的, 前一個專題介紹的委托也是包裝了一個方法的, 用前面的例子就是委派律師的只有一個人,也就是當(dāng)事人只有一個的,但是現(xiàn)實(shí)生活中顯然不是這樣的,在官司的時候律師可以同時接多個案子,也是接收多個當(dāng)時人的委派,這樣,該律師就與多個當(dāng)事人綁定在一起了, 需要了解多個當(dāng)事人的案件情況的。其實(shí)這就是生活中的委托鏈,此時這位律師不僅僅是一個人的代表律師了,而是多個當(dāng)事人的律師。生活中的委托鏈和C#中的委托鏈很類似的,現(xiàn)在就說說C#中的委托鏈到底是個什么的?

首先委托鏈就是一個委托,所以大家不要看到委托鏈感覺又是什么C#中的新特性的,然而要把多個委托鏈在一起,就必須存儲多個委托的引用,那委托鏈對象是在哪里存儲多個委托的引用的呢?還記得我們上一專題中,我們介紹的委托類型有三個非公共字段的嗎?這三個字段是——_target,methodPtr 和_invocationList,至于這三個字段具體代表什么大家可以查看我的上一專題的文章,然而_invocationList 字段正是存儲多個委托引用的地方的。

為了更好的解釋_invocationList是如何來存儲委托引用的,下面先看一個委托鏈的例子和運(yùn)行結(jié)果,然后再分析原因:

using System;

namespace DelegateTest

{
 public class Program
 {
  // 聲明一個委托類型,它的實(shí)例引用一個方法
  // 該方法回去一個int 參數(shù),返回void類型
  public delegate void DelegateTest(int parm);

  public static void Main(string[] args)
  {
   // 用靜態(tài)方法來實(shí)例化委托
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   // 用實(shí)例方法來實(shí)例化委托
   DelegateTest dtinstance = new DelegateTest(new Program().method2);
   
   // 隱式調(diào)用委托
   dtstatic(1);

   // 顯式調(diào)用Invoke方法來調(diào)用委托
   dtinstance.Invoke(1);

   // 隱式調(diào)用委托
   dtstatic(2);

   // 顯式調(diào)用Invoke方法來調(diào)用委托
   dtinstance.Invoke(2);
   Console.Read();
  }
  private static void method1(int parm)
  {
   Console.WriteLine("調(diào)用的是靜態(tài)方法,參數(shù)值為:" + parm);
  }

  private void method2(int parm)
  {
   Console.WriteLine("調(diào)用的是實(shí)例方法,參數(shù)值為:" + parm);
  }
 }

}

運(yùn)行結(jié)果:

下面就來分析下為什么會出現(xiàn)這樣的結(jié)果的:

一開始我們實(shí)例化了兩個委托變量,如下代碼:

 // 用靜態(tài)方法來實(shí)例化委托
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   // 用實(shí)例方法來實(shí)例化委托
   DelegateTest dtinstance = new DelegateTest(new Program().method2);

委托變量dtstatic和dtinstance引用的委托對象的初始狀態(tài)如下圖:

然后我們定義了一個委托類型的引用變量delegatechain,剛開始它沒有任何委托對象,是一個空引用,當(dāng)我們執(zhí)行下面的一行代碼時,

delegatechain = (DelegateTest)Delegate.Combine(delegatechain, dtstatic);

Combine方法發(fā)現(xiàn)試圖合并的是null和dtstatic,在內(nèi)部,Combine直接返回dtstatic中的對象,此時delegatechain和dtstatic變量引用的都是同一個委托對象,如下圖所示:

這時候,Combine方法發(fā)現(xiàn)delegatechain已經(jīng)引用了一個委托對象了(此時已經(jīng)引用了destatic引用的委托對象了),所以Combine會構(gòu)造一個新的委托對象(這一點(diǎn)很想String.Concat,我們簡單的使用是通過+操作符把兩個字符串連接起來,這個新的委托對象會對它的私有字段_target 和_methodPtr字段進(jìn)行初始化,然后此時_invocationList字段初始化為引用了一個委托對象的數(shù)組,這個數(shù)組的第一個元素(下標(biāo)為0)就是被初始化為引用包裝了method1方法的委托,數(shù)組的二個元素被初始化為引用包裝了method2方法的委托(也就是dtinstance引用的委托對象),最后delegaechain被設(shè)為引用新建的這個委托對象,下面是一個圖,可以幫助大家理解委托鏈(也叫多播委托):

同樣的道理,如果是添加第三個委托給委托鏈,過程也是和上面一樣的, 此時又會新建一個委托對象,此時_invocationList字段會初始化為引用一個保存這三個委托對象數(shù)組,然而有人會問了——對于已經(jīng)引用了委托對象的委托類型變量調(diào)用Combine方法后會創(chuàng)建一個新的委托對象,然后對新的這個委托對象的三個字段進(jìn)行重新初始化話,最后把之前的委托類型變量引用新創(chuàng)建的委托對象(這里就幫大家總結(jié)下委托鏈的創(chuàng)建過程),那之前的委托對象怎么辦呢? 相信大部分人會有這個疑問的,這點(diǎn)和字符串的Concat方法很像,之前的委托對象和——invocationList字段引用的數(shù)組會被垃圾回收掉(正是因為這樣,委托和字符串String一樣是不可變的)。

注意:我們還可以調(diào)用Delegate的Remove方法從鏈中刪除委托,如調(diào)用下面代碼時:

delegatechain =(DelegateTest)Delegate.Remove(delegatechain,new DelegateTest(method1));

Remove方法被調(diào)用時,它會掃描delegateChain(第一個參數(shù))所引用的委托對象內(nèi)部維護(hù)的委托數(shù)組(如果對于委托數(shù)組為空的情況下調(diào)用Remove方法將不會有任何作用,就是不會刪除任何委托引用,這里主要是說明掃描是從委托數(shù)組里進(jìn)行掃描),如果找到delegateChain引用的委托對象的_target和_methodPtr字段

和第二個參數(shù)(新創(chuàng)建的委托)中的字段匹配的委托,如果刪除之后數(shù)組中只剩下一個數(shù)據(jù)項時,就返回那個數(shù)據(jù)項(而不會去新建一個委托對象再初始化的,此時的_invocationList為null,而不是保存一個委托對象引用的數(shù)組了,具體可以Remove一個后調(diào)試看看的),如果此時數(shù)組中還剩余多個數(shù)據(jù)項,就新建一個委托對象——其中創(chuàng)建并初始化_invocationList數(shù)組(此時的數(shù)組引用的委托對象已經(jīng)少了一個了,因為用Remove方法刪除了),并且,每次Remove方法調(diào)用只能從鏈中刪除一個委托,而不會刪除有匹配的_target和_methodPtr字段的所有委托(這個大家可以調(diào)試看看的)

二、如何對委托鏈中的委托調(diào)用進(jìn)行控制

通過上面相信大家可以理解如何創(chuàng)建一個委托鏈對象的,但是從運(yùn)行結(jié)果中還可以看出,每次調(diào)用委托鏈時,委托鏈包裝的每個方法都會順序被執(zhí)行,如果委托鏈中被調(diào)用的委托拋出一個異常,這樣鏈中的后續(xù)所有對象都不能被調(diào)用,并且如果委托的前面具有一個非void的返回類型,則只有最后一個返回值會被保留,其他所有回調(diào)方法的返回值都會被舍棄,這就意味著其他所有操作的返回值都永遠(yuǎn)看不到的嗎? 事實(shí)卻不是這樣的,我們可以通過調(diào)用Delegate.GetInvocationList方法來顯式調(diào)用鏈中的每一個委托,同時可以添加一些自己的定義輸出。

GetInvocationList方法返回一個由Delegate引用構(gòu)成的數(shù)組,其中每一個數(shù)組都指向鏈中的一個委托對象。在內(nèi)部,GetInvocationList創(chuàng)建并初始化一個數(shù)組,讓數(shù)據(jù)的每一個元素都引用鏈中的一個委托,然后返回對該數(shù)組的一個引用。如果_invocatinList字段為null,返回的數(shù)組只有一個元素,該元素就是委托實(shí)例本身。下面就通過一個程序來演示下的:

namespace DelegateChainDemo
{
 class Program
 {
  // 聲明一個委托類型,它的實(shí)例引用一個方法
  // 該方法回去一個int 參數(shù),返回void類型
  public delegate string DelegateTest();

  static void Main(string[] args)
  {
   // 用靜態(tài)方法來實(shí)例化委托
   DelegateTest dtstatic = new DelegateTest(Program.method1);

   // 用實(shí)例方法來實(shí)例化委托
   DelegateTest dtinstance = new DelegateTest(new Program().method2);
   DelegateTest dtinstance2 = new DelegateTest(new Program().method3);
   // 定義一個委托鏈對象,一開始初始化為null,就是不代表任何方法(我就是我,我不代表任何人)
   DelegateTest delegatechain = null;
   delegatechain += dtstatic;
   delegatechain += dtinstance;
   delegatechain += dtinstance2;

   ////delegatechain =(DelegateTest)Delegate.Remove(delegatechain,new DelegateTest(method1));
   ////delegatechain = (DelegateTest)Delegate.Remove(delegatechain, new DelegateTest(new Program().method2));
   Console.WriteLine(Test(delegatechain));
   Console.Read();
  }

  private static string method1()
  {
   return "這是靜態(tài)方法1";
  }

  private string method2()
  {
   throw new Exception("拋出了一個異常");
  }

  private string method3()
  {
   return "這是實(shí)例方法3";
  }
  // 測試調(diào)用委托的方法
  private static string Test(DelegateTest chain)
  {
   if (chain == null)
   {
    return null;
   }

   // 用這個變量來保存輸出的字符串
   StringBuilder returnstring = new StringBuilder();

   // 獲取一個委托數(shù)組,其中每個元素都引用鏈中的委托
   Delegate[] delegatearray=chain.GetInvocationList();

   // 遍歷數(shù)組中的每個委托
   foreach (DelegateTest t in delegatearray)
   {
    try
    {
     //調(diào)用委托獲得返回值
     returnstring.Append(t() + Environment.NewLine);
    }
    catch (Exception e)
    {
     returnstring.AppendFormat("異常從 {0} 方法中拋出, 異常信息為:{1}{2}", t.Method.Name, e.Message, Environment.NewLine);
    }
   }

   // 把結(jié)果返回給調(diào)用者
   return returnstring.ToString();
  }
 }
}

運(yùn)行結(jié)果截圖:

三、總結(jié)下

本專題主要介紹如何創(chuàng)建一個委托鏈以及對于創(chuàng)建一個委托鏈的過程進(jìn)行了詳細(xì)的分享,第二部分主要先指出了委托了一些局限性,然后通過調(diào)用GetInvocationList方法來返回一個委托數(shù)組,這樣就可以通過遍歷委托數(shù)組中的每個委托來通知委托的調(diào)用過程,這樣就可以對委托鏈的調(diào)用進(jìn)行更多的控制的。到此本專題也就介紹完了,通過這三個專題對委托的介紹,相信大家會對委托有一個更深的理解,然后為什么要寫三個專題來詳細(xì)介紹委托的呢? 主要是后面要介紹的事件,Lambda表達(dá)式,Linq方面的內(nèi)容都是和委托有關(guān)系的,所以更好的理解委托將是后面特性的一個基礎(chǔ),希望這些對大家有幫助,我將在下一個專題里面介紹事件。

以上就是詳解c# 委托鏈的詳細(xì)內(nèi)容,更多關(guān)于c# 委托鏈的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#生成唯一值的方法匯總

    C#生成唯一值的方法匯總

    這篇文章主要介紹了C#生成唯一值的方法匯總,有需要的朋友可以參考一下
    2013-11-11
  • C#實(shí)現(xiàn)數(shù)獨(dú)解法

    C#實(shí)現(xiàn)數(shù)獨(dú)解法

    這篇文章介紹了C#實(shí)現(xiàn)數(shù)獨(dú)解法的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#多線程處理多個隊列數(shù)據(jù)的方法

    C#多線程處理多個隊列數(shù)據(jù)的方法

    本文將結(jié)合實(shí)例代碼,介紹C#多線程處理多個隊列數(shù)據(jù)的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • C#匿名委托與Lambda表達(dá)式詳解

    C#匿名委托與Lambda表達(dá)式詳解

    這篇文章主要為大家詳細(xì)介紹了C#匿名委托與Lambda表達(dá)式的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • 基于WPF編寫有趣的久坐提醒桌面小程序

    基于WPF編寫有趣的久坐提醒桌面小程序

    這篇文章主要為大家詳細(xì)介紹了如何基于WPF編寫一個有趣的久坐提醒桌面小程序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以動手嘗試一下
    2023-08-08
  • C#調(diào)用易語言寫的Dll文件方法

    C#調(diào)用易語言寫的Dll文件方法

    在本篇內(nèi)容里小編給大家分享的是關(guān)于C#調(diào)用易語言寫的Dll文件的方法內(nèi)容,需要的參考下。
    2018-12-12
  • 詳解如何將.NET應(yīng)用轉(zhuǎn)換成Window服務(wù)

    詳解如何將.NET應(yīng)用轉(zhuǎn)換成Window服務(wù)

    這篇文章主要為大家詳細(xì)介紹了如何將.NET8.0應(yīng)用程序轉(zhuǎn)換成Windows服務(wù),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • WPF簡單的數(shù)據(jù)庫查詢實(shí)例

    WPF簡單的數(shù)據(jù)庫查詢實(shí)例

    下面小編就為大家分享一篇WPF簡單的數(shù)據(jù)庫查詢實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11
  • C# 調(diào)用WebApi的實(shí)現(xiàn)

    C# 調(diào)用WebApi的實(shí)現(xiàn)

    這篇文章主要介紹了C# 調(diào)用WebApi的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C#圖表算法之最短路徑

    C#圖表算法之最短路徑

    本文詳細(xì)講解了C#圖表算法之最短路徑,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04

最新評論

和硕县| 尼玛县| 酉阳| 上高县| 宁远县| 都安| 阿克苏市| 招远市| 庆安县| 五常市| 当涂县| 昌黎县| 香港| 米易县| 丰镇市| 武冈市| 德阳市| 邢台县| 逊克县| 江门市| 辽阳市| 桐城市| 图们市| 芜湖县| 漯河市| 汉寿县| 海安县| 隆安县| 嘉荫县| 克什克腾旗| 同江市| 商南县| 延津县| 澄迈县| 本溪| 南涧| 和龙市| 鄂托克旗| 陆川县| 固阳县| 全南县|