CLR之委托的揭秘(一)
初識委托:
在之前的學習中我們已經可以把對象,值,數組當作參數傳遞給方法,但是有沒有可能把方法也當作參數傳遞給方法呢?有了這個想法於是就有了委托。方法當作一種參數去傳遞,但是方法有的有返回值有的沒有返回值,這如何處理?委托又用在什麽地方?通過這篇文章我們來學習一下委托的用法
委托解密:
在C#中要使用委托。必選先定義要使用的委托,在使用時需要創建該委托的一個或多個實例,以下示例展示了如何聲明委托
1 /* 2 委托的安全性非常高,所以在聲明委托時,要聲明委托返回的類型和參數類型 3 */View Code4 //聲明返回類型為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);
由於定義一個委托實際上是定義一個類,但這個類前面必須加上delegate關鍵字,所以委托可以定在類中的任何位置,也可以在名稱空間中把委托當作頂層對象定義,表面上看,委托聲明只需要一句話public delegate double TwolongsOp(long first,long second);
編譯器在讀取這行代碼時,實際上會自動為其生成一個完整的類,這個類中包含有一個構造器和Invoke,BeginInvoke,EndInvoke方法。自動生成的這個類繼承自MulticastDelegate,所以這個類也繼承了MulticastDelegate的字段,屬性和方法。這個將在委托鏈中使用其中的一些方法。
那麽經過CLR的自動編譯以後,我們就可以開始使用委托,下面代碼就是如何使用委托
1 class Program 2 { 3 //View Code聲明返回類型為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 }
實際上代碼中使用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之委托的揭秘(一)