本文介紹了 C# 中委托的定義、使用、為什麼引入委托以及委托的本質。同時,還介紹了委托鏈的使用,即將多個委托鏈接在一起,提高程式的可擴展性。 ...
之前的大部分內容,其實都是面向對象語言的共性,而這次的委托是 C# 特有的內容
1.委托的定義
C# 中的委托可以理解為函數的包裝,它使得 C# 中的函數可以作為參數來傳遞(類似於JavaScript中的高級函數),作用上相當於C++中的函數指針,C++用函數指針獲取函數的入口地址,然後通過這個指針實現對函數的操作
委托的定義和方法的定義類似,只是在前面多了一個delegate關鍵字
public delegate void MyDelegate(int para1,string para2);
委托包裝方法的條件:
- 方法的簽名必須和委托一致,方法簽名包括參數的個數、類型、順序
- 方法的返回類型要和委托一致(方法的返回類型不屬於方法簽名的一部分)
簡單來說,如圖所示:
簡單來說,就是我們將MyMethod()方法委托給了MyDelegate()去執行了
2.委托的使用
class Program {
// 1.使用delegate定義委托使用
delegate void MyDelegate(int a, int b);
public static void Main(string[] args) {
// 2.聲明委托變數d
MyDelegate d;
// 3.實例化委托變數d
d = new MyDelegate(new Program().add);
// 4.委托作為參數進行傳遞
MyMethod(d);
Console.Read();
}
public void add(int a, int b) {
int c = a + b;
Console.WriteLine("最後的結果為:{0}",c);
}
private static void MyMethod(MyDelegate mydelegate) {
// 5.在方法中調用委托
mydelegate(1, 2);
}
}
委托使用的註意點
:
- 委托實例化傳遞的參數,必須和委托定義相同,即方法的返回類型和參數個數、參數類型都碧血和委托相同,並且,傳遞的是方法名(不帶括弧)
- 委托的調用,與方法調用類似,傳遞的實際參數個數必須與委托定義一致
- 委托是方法包裝類型,所以委托的調用實際上是對包裝的方法的調用
3.為什麼引入委托
我們先看一個沒有委托的寫法
我們可以發現,沒有委托,如果我們打招呼的方式多了起來,則Greet中的switch case語句要一直寫下去,根據“開閉原則”(對擴展開發,對修改關閉),我們是不建議這樣去寫的
class Program {
public static void Main(string[] args) {
Program p = new Program();
p.Greet("李廣", "zh-cn");
}
public void Greet(string name,string language) {
switch (language) {
case "zh-cn":
ChineseGreeting(name);
break;
case "en-us":
EnlishGreeting(name);
break;
default:
EnlishGreeting(name);
break;
}
}
// 1.中國人打招呼的方式
public void ChineseGreeting(string name) {
Console.WriteLine("你好"+name);
}
public void EnlishGreeting(string name) {
Console.WriteLine("Hello"+name);
}
}
而如果我們使用了委托,我們可以不破壞原有的代碼內容,只需要在後面繼續添加新的打招呼方法就可以,這樣提高了程式的可擴展性
class Program {
public delegate void GreetDelegate(string name);
public static void Main(string[] args) {
Program p = new Program();
p.Greet("李廣", p.EnlishGreeting);
p.Greet("李廣", p.ChineseGreeting);
}
public void Greet(string name, GreetDelegate callback) {
callback(name);
}
// 1.中國人打招呼的方式
public void ChineseGreeting(string name) {
Console.WriteLine("你好"+name);
}
public void EnlishGreeting(string name) {
Console.WriteLine("Hello"+name);
}
}
4.委托的本質
class Program {
public delegate void DelegateTest(int parm);
static void Main(string[] args) {
Console.WriteLine("調用");
}
}
用以上的代碼來反編譯一下,我們發現DelegateTest委托類型使用了.class關鍵字進行標識,所以 C# 編譯器會把我們定義的委托類型,編譯成如下的類類型
IAsyncResult和EndInvoke 這兩個方法是非同步方法
我們可以對Invoke進行顯式調用,最後,我們可以清楚的看到,委托是類類型
最後我們發現,其本質也就是調用了Invoke方法來執行對應的方法
總結:
委托的本質,其實就是一個類,這個類中一共有四個方法
- 構造方法
- Invoke()調用函數參數的方法
- 一個非同步獲取方法返回值的方法
- 一個非同步執行參數方法的方法
5.委托鏈
前面都是委托封裝一個方法的情況,即一個委托只為一個方法服務,但是也有一個委托為多個方法服務的情況,C# 中把封裝多個方法的委托稱為委托鏈或多路廣播委托
5.1 委托鏈的使用
委托鏈其實就是委托類型,只是委托鏈將多個委托鏈接在一起了而已
向委托鏈中添加委托是使用 +
,那麼移除委托就是使用 -
,委托鏈中移除委托後,仍然可以將委托移動到其它委托鏈中
class Program
{
public delegate void DelegateTest();
static void Main(string[] args) {
// 1.委托1
DelegateTest delegateMethod1 = new DelegateTest(Program.method1);
// 2.委托2
DelegateTest delegateMethod2 = new DelegateTest(new Program().method2);
// 3.定義委托鏈
DelegateTest delegateChain = null;
// 4.向委托鏈中添加委托
delegateChain += delegateMethod1;
delegateChain += delegateMethod2;
delegateChain();
Console.Read();
}
private static void method1() {
Console.WriteLine("這是靜態方法");
}
private void method2() { Console.WriteLine("這是實例方法"); }
}