【博主】反骨仔 【原文】http://www.cnblogs.com/liqingwen/p/6031892.html
html
delegate 一種自定義的引用類型,它包含了特定的參數列表和返回類型。web
使用委託時,只須要對應的方法的簽名和返回類型兼容便可,不管是實例方法,抑或是靜態方法。經過調用委託的實例就至關於調用方法自己,由於委託存儲的是一個方法列表,調用委託的實例就至關於依次調用方法列表的內容。委託它將方法做爲參數進行傳遞給了其它方法,咱們經常使用的事件處理程序就是經過委託調用的方法,也是一種觀察者模式的體現。express
下面的示例演示了一個委託聲明:編程
public delegate int Del(int x, int y);
使用委託的要求是:方法簽名與返回類型兼容。能夠是靜態方法,也能夠是實例方法。 windows
類型安全,相似於 C 和 C++ 中的函數指針。安全
可將方法做爲參數進行傳遞。app
可用於定義回調方法。異步
委託能夠連接在一塊兒;例如,能夠對一個事件調用多個方法。函數
方法沒必要與委託類型徹底匹配。post
委託,一種類型,它是安全的,自定義的,委託的名稱就決定了這個委託是什麼類型。
//該委託能夠封裝 「,參數類型 string,返回類型 void」 的方法 public delegate void MyDel(string message);
委託的實例對象一般使用兩種方式進行構建,直接使用類的方法名,或者使用 Lambda 表達式,固然匿名方法也能夠。
在調用委託的時刻,咱們將傳遞到委託的參數會繼續傳遞到委託列表的方法中。若是委託列表中包含返回值的話,會將最後一個返回值返回給調用方。也就是該委託對象調用完畢的返回值。
1 //該委託名爲 MyDel,能夠封裝 「參數類型 string,返回值類型 void」 的方法 2 public delegate void MyDel(string message); 3 4 class Program 5 { 6 static void Main(string[] args) 7 { 8 //實例化委託 9 MyDel del = Print; 10 //調用委託 11 del("Hi"); 12 13 Console.Read(); 14 } 15 16 /// <summary> 17 /// 打印文本 18 /// </summary> 19 /// <remarks>這是一個可用於 MyDel 委託的方法</remarks> 20 /// <param name="message"></param> 21 private static void Print(string message) 22 { 23 Console.WriteLine(message); 24 } 25 }
委託的關鍵字是 delegate,它派生自 Delegate 類,也是 sealed,即密封類,不能做爲基類再繼續派生。
異步回調:容許以方法的形式做爲參數形式進行傳遞,並在稍後進行該委託的調用。經過這個形式使用的委託,調用方不須要知道方法的具體實現,只是簡單的把它當作一個功能便可,這相似接口的封裝。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 MyDel del = Print; 6 CallbackMethod(100, 150, del); //將委託傳遞到 CallbackMethod 方法 7 8 Console.Read(); 9 } 10 11 /// <summary> 12 /// 回調方法 13 /// </summary> 14 /// <param name="m"></param> 15 /// <param name="n"></param> 16 /// <param name="del"></param> 17 private static void CallbackMethod(int m, int n, MyDel del) 18 { 19 del((m + n).ToString()); 20 } 21 22 private static void Print(string message) 23 { 24 Console.WriteLine(message); 25 } 26 }
在這裏的 CallbackMethod 做用是,調用委託,由於它包含的是 Print() 方法的調用,因此只須要傳遞對應的 string 類型做爲參數便可。
咱們在建立委託的時候,你能夠選擇使用的是實例方法或者是靜態方法。當你使用的是實例方法時,該委託對象會同時引用該實例的對象及它的方法。委託並不關心應用引用對象的類型,它關心的是,方法簽名和返回值兼容,便可。不過,若是你建立委託對象包含的是靜態方法的時候,它是隻引用該方法的。
使用 += 能夠把多個方法添加到一個委託對象的調用列表中,調用一次委託,至關於一次性調用一堆方法。
1 //該委託能夠封裝 「名 MyDel,參數類型 string,返回值類型 void」 的方法 2 public delegate void MyDel(string message); 3 4 class MyClass 5 { 6 public void Print1(string message) 7 { 8 Console.WriteLine($"{message} - {nameof(Print1)}"); 9 } 10 11 public void Print2(string message) 12 { 13 Console.WriteLine($"{message} - {nameof(Print2)}"); 14 } 15 } 16 17 class Program 18 { 19 static void Main(string[] args) 20 { 21 var myClass = new MyClass(); 22 MyDel del1 = myClass.Print1; 23 MyDel del2 = myClass.Print2; 24 MyDel del3 = Print; 25 26 var del = del1 + del2; 27 del += del3; //這裏使用 += 28 del("Hi!"); 29 30 Console.Read(); 31 } 32 33 private static void Print(string message) 34 { 35 Console.WriteLine($"{message} - {nameof(Print)}"); 36 } 37 }
委託對象 del,他內部存儲的是一個包含三個方法的調用列表(Print一、Print2 和 Print),在你調用 del 對象時,調用列表中的方法會依次調用。
多播委託:一個委託對象調用多個方法,使用 +=。
若要從委託對象的調用列表中移除方法,須要使用 -=。
1 static void Main(string[] args) 2 { 3 var myClass = new MyClass(); 4 MyDel del1 = myClass.Print1; 5 MyDel del2 = myClass.Print2; 6 MyDel del3 = Print; 7 8 var del = del1 + del2; 9 del += del3; //使用 += 10 del("Hi!"); 11 12 Console.WriteLine("======分割線======"); 13 14 del -= del2; //使用 -= 15 del("Hi!"); 16 17 Console.Read(); 18 }
你也能夠編寫一些方法獲取調用列表中方法的數量:
1 static void Main(string[] args) 2 { 3 var myClass = new MyClass(); 4 MyDel del1 = myClass.Print1; 5 MyDel del2 = myClass.Print2; 6 MyDel del3 = Print; 7 8 var del = del1 + del2; 9 del += del3; //使用 += 10 //del("Hi!"); 11 12 var count = del.GetInvocationList().Length; //獲取委託調用列表中方法的數量 13 Console.WriteLine(count); 14 15 Console.WriteLine("======分割線======"); 16 17 del -= del2; //使用 -= 18 //del("Hi!"); 19 20 count = del.GetInvocationList().Length; //獲取委託調用列表中方法的數量 21 Console.WriteLine(count); 22 23 Console.Read(); 24 }
多播委託派生自 MulticastDelegate,也是繼承自 Delegate的,經常使用於事件處理中。
【參考】https://msdn.microsoft.com/zh-cn/library/windows/apps/ms173171(v=vs.120).aspx
【參考】微軟官方文檔