1. 程式人生 > >CLR之委托的揭秘(一)

CLR之委托的揭秘(一)

這一 res 事情 .cn log 直接 net 文章 自動編譯

初識委托:

在之前的學習中我們已經可以把對象,值,數組當作參數傳遞給方法,但是有沒有可能把方法也當作參數傳遞給方法呢?有了這個想法於是就有了委托。方法當作一種參數去傳遞,但是方法有的有返回值有的沒有返回值,這如何處理?委托又用在什麽地方?通過這篇文章我們來學習一下委托的用法

委托解密:

在C#中要使用委托。必選先定義要使用的委托,在使用時需要創建該委托的一個或多個實例,以下示例展示了如何聲明委托

技術分享
1  /*
2      委托的安全性非常高,所以在聲明委托時,要聲明委托返回的類型和參數類型
3          */
4 //聲明返回類型為double 兩個參數類型為long的委托 5 public delegate double TwolongsOp(long first,long second); 6 //聲明返回類型為string 無參的委托 7 public delegate string Getstring(); 8 //聲明返回類型為void 參數類型為int的委托 9 public delegate void IntMethodInvoker(int x);
View Code

由於定義一個委托實際上是定義一個類,但這個類前面必須加上delegate關鍵字,所以委托可以定在類中的任何位置,也可以在名稱空間中把委托當作頂層對象定義,表面上看,委托聲明只需要一句話public delegate double TwolongsOp(long first,long second);

,但從CLR角度來看,委托實際上是很復雜的,在使用委托之前先來看一下,底層是如何處理這一句話的。

編譯器在讀取這行代碼時,實際上會自動為其生成一個完整的類,這個類中包含有一個構造器和Invoke,BeginInvoke,EndInvoke方法。自動生成的這個類繼承自MulticastDelegate,所以這個類也繼承了MulticastDelegate的字段,屬性和方法。這個將在委托鏈中使用其中的一些方法。

那麽經過CLR的自動編譯以後,我們就可以開始使用委托,下面代碼就是如何使用委托

技術分享
 1 class Program
 2     {
 3         //
聲明返回類型為string 無參的委托 4 public delegate string Getstring(); 5 static void Main(string[] args) 6 { 7 int x = 40; 8 //實例化委托,並且將int的ToString()方法當作參數傳遞給委托 9 Getstring getstring = new Getstring(x.ToString); 10 //語法糖:簡化委托調用和使用new效果一樣 11 Getstring getstring1 = x.ToString; 12 //調用委托方法 13 Console.WriteLine(getstring()); 14 //CLR生成的類中就包含的方法安全調用 15 Console.WriteLine(getstring1.Invoke()); 16 } 17 }
View Code

實際上代碼中使用getstring()方法調用和使用Invoke()調用是相同的,因為getstring()方法是委托類型的一個變量,C#編譯器會用getstring.Invoke()代替getstring(),如果為了減少輸入量,只需要委托示例,就可以只傳送地址,這稱為委托判斷。

委托鏈:

鏈式語法在C#中非常常見,Linq就是典型的鏈式方法調用,而委托也支持鏈式方法調用,委托鏈指的就是委托對象的集合,利用鏈式調用集合中的委托所代表的全部方法,但是委托鏈是有限制和缺點的,委托鏈中間方法的返回值會被丟棄無法獲取,所以委托返回值最好是void,如果是帶有返回值的,會返回最後一個方法的返回值。

舉個例子,如果我委托別人幫我去拿一個快遞,我又告訴他回來路上順便幫我帶份飯,這是兩件事情,如果這兩件事都只是去做,不需要拿到返回值,那麽委托鏈可以滿足,但是如果我要求兩個方法,第一個方法要把快遞返回到我手上,第二個方法飯也要返回到我手上,那麽就無法獲取第一個方法的返回值,也就是說我只能拿到飯,而拿不到快遞。接下來看代碼比較

技術分享
 1  //聲明返回類型為string 無參的委托
 2         public delegate string Getstring();
 3         static void Main(string[] args)
 4         {
 5             //實例化委托鏈
 6             Getstring getstatus = null;
 7             //語法糖:支持+=/-=添加方法/移除方法
 8             getstatus += TakeExpress;
 9             getstatus += beltfood;
10             //獲得結果
11             Console.WriteLine(getstatus());
12         }
13         //取快遞方法,返回的string當作實體類型看
14        public static string TakeExpress()
15         {
16             return "你的快遞是XX,已經為你取了";
17         }
18          //帶飯方法,返回的string當作實體類型看
19         public static string beltfood()
20         {
21            return "為你帶了一份黃燜雞米飯";
22         }
View Code

技術分享

兩個方法最終只輸出了最後一個方法的返回值,我們得到了一份黃燜雞米飯,但是快遞沒有得到,於是我們修改以下以上代碼,改為如下,可以看到兩個方法都被執行了

技術分享
 1  //聲明返回類型為string 無參的委托
 2         public delegate void Getstring();
 3         static void Main(string[] args)
 4         {
 5             //實例化委托鏈
 6             Getstring getstatus = null;
 7             //語法糖:支持+=/-=添加方法/移除方法
 8             getstatus += TakeExpress;
 9             getstatus += beltfood;
10             //獲得結果
11             getstatus();
12         }
13         public static void TakeExpress()
14         {
15             Console.WriteLine("你的快遞是XX,已經為你取了");
16         }
17         public static void beltfood()
18         {
19             Console.WriteLine("為你帶了一份黃燜雞米飯");
20         }
View Code

技術分享

匿名委托:

匿名方法在.NET 中提高了 代碼的可讀性和優雅性。對於更多操作較少的方法直接寫為匿名函數,這樣會大大提高代碼的可讀性。這裏有兩個值得註意的地方: 第一,不能使用跳轉語句跳轉到該匿名方法外,第二 不能使用ref,out修飾的參數,下面是一個匿名委托的調用

技術分享
   //聲明返回類型為string 無參的委托
        public delegate string Getstring(string str);
        static void Main(string[] args)
        {
             //直接在委托上完善方法
            Getstring Spkeak = delegate (string str)
            {
                if (str == "啞巴")
                {
                    return "我是啞巴,我不能說話";
                }
                return "我會說話"; 
            };

            Console.WriteLine(Spkeak("啞巴"));
View Code

小結:

委托是一種比較常用的函數回掉方法,常用於某種情況下觸發委托。

CLR之委托的揭秘(一)