文章目錄
1、C#委託是什麼?(Delegate)
C# 中的委託(Delegate)類似於 C 或 C++ 中函數的指針。委託(Delegate) 是存有對某個方法的引用的一種引用類型變量。引用可在運行時被改變。
委託(Delegate)特別用於實現事件和回調方法。所有的委託(Delegate)都派生自 System.Delegate 類。
我們知道,委託是方法的抽象,它存儲的就是一系列具有相同簽名和返回值類型的方法的地址。調用委託的時候,委託包含的所有方法將被執行。
2、聲明委託
委託聲明決定了可由該委託引用的方法。委託可指向一個與其具有相同標籤的方法。
例如,假設有一個委託:
public delegate void NoReturnWithPara(string s);
上面的委託可被用於引用任何一個帶有一個單一的 string 參數,且無返回值的方法。
聲明委託的語法如下:
delegate <return type> <delegate-name> <parameter list>
3、實例化委託
一旦聲明瞭委託類型,委託對象必須使用 new 關鍵字來創建,且與一個特定的方法有關。當創建委託時,傳遞到 new 語句的參數就像方法調用一樣書寫,但是不帶有參數。例如:
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen); //傳入的是方法名
printString ps2 = new printString(WriteToFile); //同上
下面的實例演示了委託的聲明、實例化和使用,該委託可用於引用帶有兩個整型參數的方法,並返回一個整型值。
using System;
namespace MyDelegate
{
/// <summary>
/// 委託:是一個類,繼承自System.MulticastDelegate,裏面內置了幾個方法
/// </summary>
public delegate int WithReturnWithPara(int x, int y);
public class DelegateDemo
{
static int num = 10;
public static int AddNum(int p, int n)
{
num += p + n;
return num;
}
public static int MultNum(int q, int m)
{
num *= q * m;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 創建委託實例
WithReturnWithPara dl1 = new WithReturnWithPara(AddNum);
WithReturnWithPara dl2 = new WithReturnWithPara(MultNum);
// 使用委託對象調用方法
dl1(2, 3);
Console.WriteLine("num 值爲: {0}", getNum());
dl2.Invoke(2, 3);
Console.WriteLine("num 值爲: {0}", getNum());
Console.ReadKey();
}
}
}
當上面的代碼被編譯和執行時,它會產生下列結果:
num 值爲: 15
num 值爲: 90
4、委託的多播(Multicasting of a Delegate)
委託對象可使用 “+” 運算符進行合併。一個合併委託調用它所合併的兩個委託。只有相同類型的委託可被合併。"-" 運算符可用於從合併的委託中移除組件委託。invoke的時候可以按順序執行
使用委託的這個有用的特點,您可以創建一個委託被調用時要調用的方法的調用列表。這被稱爲委託的 多播(multicasting),也叫組播。下面的程序演示了委託的多播:
using System;
namespace MyDelegate
{
/// <summary>
/// 委託:是一個類,繼承自System.MulticastDelegate,裏面內置了幾個方法
/// </summary>
public delegate int WithReturnWithPara(int x, int y);
public class DelegateDemo
{
static int num = 10;
public static int AddNum(int p, int n)
{
num += p + n;
return num;
}
public static int MultNum(int q, int m)
{
num *= q * m;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
// 創建委託實例
WithReturnWithPara dl;
WithReturnWithPara dl1 = new WithReturnWithPara(AddNum);
WithReturnWithPara dl2 = new WithReturnWithPara(MultNum);
dl = dl1;
dl += dl2;
//調用多播
dl(2, 3);
Console.WriteLine("num 值爲: {0}", getNum());
Console.ReadKey();
}
}
}
以上代碼的執行結果:
num 值爲: 90
5、匿名方法
匿名方法是在初始化委託時內聯聲明的方法。
基本結構:
deleage( 參數 ) { 語句塊 }
例如:
delegate int MyDel (int x); //定義一個委託
MyDel del = delegate(int x){ return x; };
6、Lambda表達式
Lambda表達式主要用來簡化匿名方法的語法。在匿名方法中,delegate關鍵字有點多餘,因爲編譯器已經知道我們將方法賦值給委託。通過幾個簡單步驟,我們就可以將匿名方法轉換爲Lambda表達式:
刪除delegate關鍵字
在參數列表和匿名方法主體之間防Lambda運算符=>。Lambda運算符讀作"goes to"。
MyDel del = delegate(int x) { return x; };//匿名方法
MyDel del2 = (int x) => {return x;};//Lambda表達式
MyDel del3 = x => {return x};//簡寫的Lambda表達式
7、泛型委託
如果你知道泛型,那麼就很容易理解泛型委託,說白了就是含有泛型參數的委託,例如:
public delegate T Calculator<T> (T arg);
場景使用,如下:
public delegate T Calculator<T>(T arg);
class Program {
static int Double(int x) { return x * 2; }
static void Main(string[] args) {
int[] values = { 1, 2, 3, 4 };
Utility.Calculate(values, Double);
foreach (int i in values){
Console.Write(i + " "); // 2 4 6 8
Console.ReadKey();
}
}
}
class Utility {
public static void Calculate<T>(T[] values, Calculator<T> c) {
for (int i = 0; i < values.Length; i++)
values[i] = c(values[i]);
}
}
8、Func 和 Action委託
泛型委託,能適用於任何返回類型和任意參數(類型和合理的個數)的通用委託。
以下的 in 表示參數,out 表示返回結果
Func委託:有返回值的泛型委託
delegate TResult Func<out TResult> ();
delegate TResult Func<in T, out TResult> (T arg);
delegate TResult Func<in T1, in T2, out TResult> (T1 arg1, T2 arg2);
... 一直到 T16
Action委託:無返回值的泛型委託
delegate void Action ();
delegate void Action <in T> (T arg);
delegate void Action <in T1, in T2> (T1 arg1, T2 arg2);
... 一直到 T16
Func 和 Action 委託,除了ref參數和out參數,基本上能適用於任何泛型委託的場景,非常好用。