都說C#是C語言版的Java,它是基於Java的基礎上,增加的更多的獨有的語言功能,而委託就是其中之一,而也就是委託讓我感覺到從Java轉到C#的一個大難點。
委託是通過delegate關鍵字來定義,簡單來說,委託是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞。這方面就有些相似於JavaScript的函數,它也是能夠將函數作爲參數進行傳遞。至於爲什麼要這麼做,其原理是觀察者設計模式,這裏我不做詳細說明。
進入正題,首先我先給出這三者之間的從屬關係:委託->匿名表達式->Lambda表達式。
從關係式不難看出,Lambda表達式一定能夠轉化成匿名表達式和原始的委託方式,而匿名表達式也一定能夠轉換成原始的委託方式。
上代碼:
/ //定義委託類型
delegate int calculator(int x, int y);
static void Main(string[] args)
{
//初始化委託類型(命名方法),注意是add不是add()
calculator add1 = new calculator(add);
//匿名方法是通過使用 delegate 關鍵字創建委託實例來聲明的
calculator add2 = delegate (int a, int b)
{
return a + b;
};
//任何 Lambda 表達式都可以轉換爲委託類型
//表達式 lambda
calculator add3 = (a, b) => a + b;
//Func 類型:有任意返回值的委託類型,最後一個泛型是返回值類型
Func<int, int, int> add4 = (a, b) => a + b;
//給委託變量再綁定或者刪除一個方法
add1 += sub;
//add1 -= sub;
//add1()只會輸出最近的那個函數的結果
Console.WriteLine(add1(1, 6));
Console.WriteLine(add2(2, 6));
Console.WriteLine(add3(3, 6));
Console.WriteLine(add4(4, 6));
}
private static int sub(int a, int b)
{
return 4 * a - b;
}
private static int add(int a, int b)
{
return 2 * a + b;
}
上述代碼用4種方式實現一個加法功能:
第一種方式是最原始的委託使用方式,定義,聲明,初始化,調用。
第二種方式是匿名方法的形式,通過delegate關鍵字將所需要綁定的方法直接內部實現。
第三種方式是 Lambda 表達式,進一步簡化第二種方式的代碼,變得更加簡潔美觀。
第四種方式是調用 .NET Core 框架內部已有的委託類型,此方式實現可重用。(推薦的使用方式)
由於委託的參數是方法,所以也可以將多個方法賦給同一個委託,當調用這個委託的時候,將依次調用其所綁定的方法。
在 .NET Core 框架內部定義的常用委託類型有兩種:Action 類型與Func 類型。
它倆都是泛型類型,只不過前者是具有 void 返回類型的委託類型,而後者是有任意返回值的委託類型。
在C#中Lambda 表達式具體來說也有多種類型,上述代碼的Lambda 表達式屬於表達式 lambda,基礎常用的還有語句Lambda和含標準查詢運算符的 lambda。
上代碼:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
//匿名方法
int oddNumbers1 = numbers.Count(delegate (int n)
{
return n % 2 == 0;
});
Console.WriteLine(oddNumbers1);
//含標準查詢運算符的 lambda
int oddNumbers2 = numbers.Count(n => n % 2 == 1);
Console.WriteLine(oddNumbers2);
//Action 類型:具有 void 返回類型的委託類型
//匿名方法
Action<int[], int, int> change1 = delegate (int[] nums, int a, int b)
{
var tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
};
//語句Lambda
Action<int[], int, int> change2 = (nums, a, b) =>
{
var tmp = nums[a];
nums[a] = nums[b];
nums[b] = tmp;
};
change1(numbers, 0, 1);
change2(numbers, 2, 3);
foreach (var item in numbers)
{
Console.Write(item + " ");
}
相信經過上述兩個案例的對比代碼,這三者之間的關係應該就很容易理解了。
其實剛開始就想直接寫出Lambda的確挺難的,還是先從委託開始慢慢過渡到熟悉匿名函數,最後就能輕易的掌握Lambda表達式!