什么是委托
委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞,這種將方法動態地賦給參數的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時使得程序具有更好的可擴展性。
委托是一種動態調用方法的類型,屬於引用型。
委托是對方法的抽象和封裝。委托對象實質上代表了方法的引用(即內存地址)
可以理解為函數的一個包裝,它使得c#中的函數可以作為參數來被傳遞
簡單理解是這樣的
比如您要管您的孩子,把孩子送進了幼兒園
OK,此時您就把您的孩子委托給了幼兒園
當幼兒園放學,將孩子交還給您的手中則是委托的回調
當然我這里的例子是說異步委托調用,您也可以同步
什么是同步委托調用?
您去銀行存錢,把錢給櫃員,他們幫你點鈔,存款然后給您存折或卡
那么您就相當於把錢委托給了櫃員讓他去執行存錢的這個函數
委托的定義
1. 以delegate關鍵字開頭。
2. 返回類型+委托類型名+參數列表
public delegate void MyDelegate(int para1, string para2);
委托能包裝的方法是有一定限制的,例如能被前面的委托類型MyDelegate包裝的方法需要滿足以下條件:
1.方法的返回類型必須為void;
2.方法必須有兩個參數,並且第一個參數應為int類型,第二個參數為string類型。
總結:可以被委托包裝的方法必須滿足以下規則:
1.方法的簽名必須與委托一致,方法簽名包括參數的個數、類型和順序;
2.方法的返回類型要和委托一致,注意,方法的返回類型不屬於方法簽名的一部分。

委托的使用
//委托使用的演示
class Program { //1.使用delegate關鍵字來定義一個委托類型
public delegate void MyDelegate(int para1, int para2); static void Main(string[] args) { //2.聲明委托變量d
MyDelegate d; //3.實例化委托類型,傳遞的方法也可以為靜態方法,這里傳遞的是實例方法
d = new MyDelegate(new Program().Add); //4.委托類型作為參數傳遞給另一個方法
MyMethod(d); Console.ReadKey(); } void Add(int para1,int para2) { int sum = para1 + para2; Console.WriteLine("兩個數的和為:" + sum); } private static void MyMethod(MyDelegate mydelegate) { //5.在方法中調用委托
mydelegate(1, 2); } }
從以上代碼可以看出,使用委托的步驟為:定義委托類型—聲明委托變量—實例化委托—作為參數傳遞給方法—調用委托。如下具體分析委托的使用過程。
(1)定義委托類型:public delegate void MyDelegate(int para1, int para2) 其定義方式類似於方法的定義,只是多了一個delegate關鍵字。
(2)聲明委托變量:MyDelegate d;既然委托是一種類型,那么可以使用委托來聲明一個委托變量,相當於int a;
(3)實例化委托: d = new MyDelegate(new Program().Add);。第二步只是聲明了委托變量,但並沒有將它實例化。類的實例化使用new關鍵字來實現,而委托也屬於類類型,所以委托的實例化也使用new關鍵字來進行的。這里需要注意的是,委托的實例化是用一個方法名(不能帶左右括號)作為參數,並且該方法的定義必須符合委托的定義,即該方法的返回類型、參數個數和類型必須與委托定義中的一樣。這樣,前面3步就好比構造了一個律師對象,而方法InstanceMethod好比是當事人的方法。
(4)作為參數傳遞給方法:MyMethod(d);。委托使用得在C#中,可以把一個方法作為另一個方法的參數,而委托可以看作是一個包裝方法的對象。
(5)在方法中調用委托:MyMethod(d);。委托使用得在c#中,可以把一個方法作為另一個方法的參數,而委托可以看作是一個包裝方法的對象。
總結:在使用委托時,需要注意以下幾個問題。
1.在第三步中,被傳遞的方法的定義必須與委托定義相同,即方法的返回類型和參數個數、參數類型都必須與委托相同。並且,傳遞的是方法名,方法名后不能帶有左右括號。
2.在第五步中,委托的調用與方法調用類似,傳遞的實參類型和個數必須與委托定義一致。
3.由於委托是方法的包裝類型,所以對委托的調用也就是對其所包裝的的方法的調用,上面第5步時間上是調用了Add方法來對傳入的實參進行計算。
為什么要使用委托
委托使得一個方法可以作為另一個方法的參數進行傳遞,這就是委托最大的作用。使用委托可以將同類型的方法綁定到同一個變量上,當調用此變量時就可以一次調用綁定的方法,很方便。如下例子:
例如我們要實現一個打招呼的方法,而每個國家打招呼的方式都不一樣,剛開始我們可能會像下面這樣實現打招呼的方法:
public void Greeting(string name,string language) { switch (language) { case "zh-cn": ChineseGreeting(name); break; case "en-us": EnglishGreeting(name); break; default: EnglishGreeting(name); break; } } public void EnglishGreeting(string name ) { Console.WriteLine("Hello, " + name); } public void ChineseGreeting(string name) { Console.WriteLine("你好, " + name); }
若后續我們需要添加德國、日本等打招呼方法,就必須修改Greeting方法內的case語句,來適應新的需求,這樣特別不方便。有了委托,我們就可以把函數作為參數,並像如下代碼實現Greeting方法:
public delegate void GreetingDelegate(string name); static void Main(string[] args) { //引入委托
Program p = new Program(); p.Greeting("小葉", p.ChineseGreeting); p.Greeting("Tommy Li", p.EnglishGreeting); Console.Read(); } public void Greeting(string name,GreetingDelegate callback) { callback(name); } public void EnglishGreeting(string name) { Console.WriteLine("Hello, " + name); } public void ChineseGreeting(string name) { Console.WriteLine("你好, " + name); }
如下,增加德國人打招呼:
class Program { public delegate void GreetingDelegate(string name); static void Main(string[] args) { //引入委托
Program p = new Program();
p.Greeting("小葉", p.ChineseGreeting); p.Greeting("Tommy Li", p.EnglishGreeting); p.Greeting("Ha Wa", p.GermanyGreeting); Console.Read(); } public void Greeting(string name,GreetingDelegate callback) { callback(name); } public void EnglishGreeting(string name) { Console.WriteLine("Hello, " + name); } public void ChineseGreeting(string name) { Console.WriteLine("你好, " + name); } public void GermanyGreeting(string name) { Console.WriteLine("Hallo, " + name); } }
委托鏈的使用
委托鏈其實就是委托類型,只是委托鏈把多個委托鏈接在一起而已,也就是說,我們把鏈接了多個方法的委托稱為委托鏈或多路廣播委托。如下:
public delegate void DelegateTest(); static void Main(string[] args) { //用靜態方法來實例化委托
DelegateTest dtstatic = new DelegateTest(Program.method1); DelegateTest dtinstance = new DelegateTest(new Program().method2); //定義一個委托對象,一開始初始化為null,即不代表任何方法。
DelegateTest delegatechain = null; //使用 “+”符號鏈接委托,鏈接多個委托后就成為了委托鏈 delegatechain += dtstatic; delegatechain += dtinstance; //調用委托鏈
delegatechain(); Console.Read(); }
private static void method1() { Console.WriteLine("這是靜態方法"); } //實例方法
private void method2() { Console.WriteLine("這是實例方法"); }
從委托鏈中移除委托
public delegate void DelegateTest(); static void Main(string[] args) { //用靜態方法來實例化委托
DelegateTest dtstatic = new DelegateTest(Program.method1); DelegateTest dtinstance = new DelegateTest(new Program().method2); //定義一個委托對象,一開始初始化為null,即不代表任何方法。
DelegateTest delegatechain = null; //使用 “+”符號鏈接委托,鏈接多個委托后就成為了委托鏈 delegatechain += dtstatic; delegatechain += dtinstance; //使用 “-”運算符 移除委托
delegatechain -= dtstatic; //調用委托鏈
delegatechain(); Console.Read(); } private static void method1() { Console.WriteLine("這是靜態方法"); } //實例方法
private void method2() { Console.WriteLine("這是實例方法"); }
多播委托
如果要調用多個方法,就需要多次顯式調用這個委托。但是委托也可以包含多個方法,這種委托稱為多播委托。
如果調用多播委托就可以按順序連續調用多個方法。為此,委托的簽名就必須返回void;否則,就只能得到委托調用的最后一個方法的結果。
例如:
-
Action operations=方法一;operartion+=方法二;
-
也可以 委托1=方法1;委托二=方法2;委托3=委托1+委托2。
所以當調用委托3時,委托1和委托2會同時執行,與第一種實現多播委托一個道理。
但是多播委托還有一個缺陷,一旦一個委托發生異常,其他委托都會停止。為了避免這個問題,應自己迭代方法列表。Delegate類定義GetInvocationList()方法,它返回一個Delegate對象數組。現在可以使用這個委托調用與委托直接相關的
方法,捕獲異常,並繼續下一次迭代。(.net core 中間件)
匿名方法
到目前為止,要想使委托工作,方法名必須已經存在。但還有另外一種使用委托的方式:匿名方法。
匿名方法(Anonymous methods) 提供了一種傳遞代碼塊作為委托參數的技術。匿名方法是沒有名稱只有主體的方法。
在匿名方法中您不需要指定返回類型,它是從方法主體內的 return 語句推斷的。
編寫匿名方法的語法
匿名方法是通過使用 delegate 關鍵字創建委托實例來聲明的。例如:
delegate void NumberChanger(int n); ... NumberChanger nc = delegate(int x) { Console.WriteLine("Anonymous Method: {0}", x); };
代碼塊 Console.WriteLine("Anonymous Method: {0}", x); 是匿名方法的主體。
委托可以通過匿名方法調用,也可以通過命名方法調用,即,通過向委托對象傳遞方法參數。
例如:
nc(10);
實例
下面的實例演示了匿名方法的概念:
using System; delegate void NumberChanger(int n); namespace DelegateAppl { class TestDelegate { static int num = 10; public static void AddNum(int p) { num += p; Console.WriteLine("Named Method: {0}", num); } public static void MultNum(int q) { num *= q; Console.WriteLine("Named Method: {0}", num); } static void Main(string[] args) { // 使用匿名方法創建委托實例
NumberChanger nc = delegate(int x) { Console.WriteLine("Anonymous Method: {0}", x); }; // 使用匿名方法調用委托
nc(10); // 使用命名方法實例化委托
nc = new NumberChanger(AddNum); // 使用命名方法調用委托
nc(5); // 使用另一個命名方法實例化委托
nc = new NumberChanger(MultNum); // 使用命名方法調用委托
nc(2); Console.ReadKey(); } } }
當上面的代碼被編譯和執行時,它會產生下列結果:

匿名方法是用作委托的參數的一段代碼,用匿名方法定義委托的語法與前面的定義並沒有區別,但在實例化委托時,就有了區別。下面是一個非常簡單的代碼,它說明了如何使用匿名方法:
Func<string,string> anonDel=delegate(string param) { param+=mid; param+=" and this was added to the string."; return param; }
使用匿名方法的規則很明顯,它前面是關鍵字delegate,后面是一個字符串參數.
使用匿名方法
- 聲明委托變量時候作為初始化表達式。
- 組合委托時在賦值語句的右邊。
- 為委托增加事件時在賦值語句的右邊。
匿名方法語法
delegate (parameters ){implementationcode}; 關鍵字 參數 方法體
匿名方法不會聲明返回值類型。但是匿名方法返回值類型必須和委托返回值一樣。
我們可以使圓括號為空,或省略圓括號來簡化匿名方法的參數列表。但是僅在下面兩項都為真的情況下才可以這么做。
- 委托的參數列表不包含任何out參數的委托。
- 匿名方法不使用任何參數。
class Program { delegate int otherdel(int param); public static void Main() { otherdel del = delegate { cleanup(); printMessage(); }; } }
params參數
如果委托參數包含params參數,那么params關鍵字就會被匿名方法的參數列表忽略。如下:
delegate int otherdel(int x,params int y); otherdel del = delegate(int x,int y) { };
參考鏈接:https://www.cnblogs.com/zhan520g/p/10917053.html

