Linq查詢與高級C#編程機器理論研究基礎
C#委托解決的是對象之間的逆向傳遞問題僚害,其次缴饭,委托還有其他的用途(匿名方法暑劝、Lambda表達式、和泛型結合)颗搂,涉及到高級編程中(LInq查詢担猛、擴展方法)的底層原理。
一丢氢、匿名方法傅联、Lambda表達式
1、匿名方法
概念:一個只有關鍵字delegate疚察、方法參數蒸走、方法體,但沒有具體的名稱貌嫡,這種方法稱為匿名方法
好處:將具體方法和委托直接關聯到一起比驻,如果我們基于委托只需要一個方法的時候,匿名方法顯得更加簡單
CalculatorDelegate cal2 = delegate (int a, int b)
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? return a - b;
? ? ? ? ? ? ? };
2岛抄、Lambda表達式
C#3.0以后别惦,可以使用Lambda表達式更加簡練地編寫程序塊。
//將匿名方法使用Lambda表達式簡化編寫
? ? ? ? ? ? CalculatorDelegate cal3 = (int a, int b) => { return a + b};
//進一步簡化:假如方法中只有一行代碼
? ? ? ? ? ? CalculatorDelegate cal4 = (a, b) => a - b;
【1】在Lambda表達式中夫椭,參數類型可以是明確類型掸掸,也可以是推斷類型
【2】如果是推斷類型,則參數類型可以由編譯根據上下文自動推斷出來
【3】運算符=>讀作goes to,運算符左邊輸入參數(如果有)扰付,右邊是表達式或語句塊
【4】表達式兩種方式:
(input args)=>表達式
(input args)=>{語句1堤撵;語句2;語句3……}
【5】Lambda表達式與匿名方法的比較
(1)Lambda表達式本身就是匿名方法
(2)Lambda表達式允許不指明參數類型悯周、但是匿名方法必須明確
(3)Lambda表達式允許單一的表達式或多條語句組成粒督,而匿名方法不允許單一表達式
例:
public void test()
? ? ? ? {
? ? ? ? ? ? //【1】委托關聯獨立的方法
? ? ? ? ? ? CalculatorDelegate cal1 = Add;
? ? ? ? ? ? //【2】委托關聯匿名方法
? ? ? ? ? ? CalculatorDelegate cal2 = delegate (int a, int b)
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? return a - b;
? ? ? ? ? ? ? };
? ? ? ? ? ? //【3】將匿名方法使用Lambda表達式簡化編寫
? ? ? ? ? ? CalculatorDelegate cal3 = (int a, int b) => { return a + b};
? ? ? ? ? ? //進一步簡化:假如方法中只有一行代碼
? ? ? ? ? ? CalculatorDelegate cal4 = (a, b) => a - b;
? ? ? ? ? ? sayHelloDelegate sayHello = () => "歡迎你";
? ? ? ? ? ? Console.WriteLine("通過匿名方法計算:20-30="+cal2(20,30));
? ? ? ? }-
? ? ? ? private int Add(int a, int b)
? ? ? ? {
? ? ? ? ? ? return a + b;
? ? ? ? } //根據委托的使用可以繼續(xù)添加其他方法
? ? ? ? public delegate int CalculatorDelegate(int a, int b);
? ? ? ? public delegate string sayHelloDelegate();
? ? }
二、自定義泛型委托
1禽翼、為什么要使用泛型委托屠橄?
普通委托在數據類型上的限制是非常嚴格的,無法適應需求變化
2闰挡、泛型委托定義:本質上和泛型方法非常類似锐墙,泛型委托關聯的時候,可以是具體方法长酗、匿名方法溪北、Lambda表達式
/// <summary>
? ? /// 泛型委托
? ? /// </summary>
? ? class GenericDelegate
? ? {
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? //使用泛型委托:具體方法
? ? ? ? ? ? MyGenericDelegate<int> myDelegate1 = Add;
? ? ? ? }
? ? ? ? //根據委托定義方法
? ? ? ? static int Add(int a ,int b)
? ? ? ? {
? ? ? ? ? ? return a + b;
? ? ? ? }
? ? ? ? static double Sub(double a,double b)
? ? ? ? {
? ? ? ? ? ? return a - b;
? ? ? ? }
? ? ? ? public delegate int MyGenericDelegate<T>(T parameter1, T parameter2);
3、問題引出:如果使用多個參數夺脾,按照上述方法不得不定義很多這種泛型委托之拨,非常麻煩
三、系統(tǒng)泛型委托
為了方便開發(fā)者咧叭,.NET基類庫中針對常用的情況蚀乔,提供了預定委托。這些委托使用非常廣泛
兩種方式:一種是有返回值Func<args>菲茬,一種是沒有返回值Action<args>
Action<args>在多線程中用的非常多
Func<args>在linq中用的非常多
Func<args>
/// <summary>
? ? /// 有返回值的系統(tǒng)類型的泛型委托
? ? /// 目的:為了方便開發(fā)者吉挣,.NET基類庫中針對常用的情況,提供了預定委托婉弹。這些委托使用非常廣泛
? ? /// </summary>
? ? class FunDelegateDemo
? ? {
? ? ? ? #region Func委托的基本使用
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? //【1】Func關聯具體方法
? ? ? ? ? Func<int, int, double> myfunc1= Add1;
? ? ? ? ? ? //【2】Func直接使用Lambda表達式
? ? ? ? ? ? Func<int, int, double> myFunc = (a, b) => a + b;
? ? ? ? }
? ? ? ? private double Add1(int a, int b)
? ? ? ? {
? ? ? ? ? ? return a + b;
? ? ? ? }
? ? ? ? #endregion
? ? ? ? #region Func委托的重要使用
? ? ? ? //問題:給定一個數組睬魂,從數組中指定位置抽取3個數,求和镀赌,求積
? ? ? ? //思考:運算的要求不一樣(求和氯哮,求積),兩種運算可以單獨作為方法
? ? ? ? ? ? #region 普通方法
? ? ? ? ? ? public int Sum(int[] nums, int from, int to)
? ? ? ? {
? ? ? ? ? ? int result = 0;
? ? ? ? ? ? for (int i = from; i <= to; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? result += nums[i];
? ? ? ? ? ? }
? ? ? ? ? ? return result;
? ? ? ? }
? ? ? ? ? ? public int Mul(int[] nums, int from, int to)
? ? ? ? {
? ? ? ? ? ? int result = 1;
? ? ? ? ? ? for (int i = from; i <= to; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? result *= nums[i];
? ? ? ? ? ? }
? ? ? ? ? ? return result;
? ? ? ? }//還可以繼續(xù)加新的方法
? ? ? ? ? ? public void Test2()
? ? ? ? {
? ? ? ? ? ? int[] nums = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
? ? ? ? ? ? int result1 = Sum(nums, 0, 2);
? ? ? ? ? ? Console.WriteLine("10,9,8求和為:" + result1);
? ? ? ? ? ? int result2 = Mul(nums, 0, 2);
? ? ? ? ? ? Console.WriteLine("10,9,8求積為:" + result1);
? ? ? ? }
? ? ? ? ? ? #endregion
? ? ? ? ? ? #region 使用Func委托商佛,將“運算”本身作為方法參數
? ? ? ? ? ? public int Operation(Func<int,int,int> method ,int[] nums,int from,int to? )
? ? ? ? ? ? {
? ? ? ? ? ? int result = nums[from];//把第一個值作為基數
? ? ? ? ? ? for (int i = from+1; i <= to; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? result =method(result,nums[i]);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? return result;
? ? ? ? ? ? }
? ? ? ? public void Test3()
? ? ? ? {
? ? ? ? ? ? int[] nums = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
? ? ? ? ? ? //將Func作為方法參數喉钢,結合Lambda表達式
? ? ? ? ? ? int result1 = Operation((a,b)=>a+b, nums,0, 2);
? ? ? ? ? ? Console.WriteLine("10,9,8求和為:" + result1);
? ? ? ? ? ? int result2 = Operation((a, b) => a * b, nums, 0, 2);
? ? ? ? ? ? Console.WriteLine("10,9,8求積為:" + result2);
? ? ? ? }
? ? ? ? #endregion
? ? ? ? #endregion
? ? }
}
Func<args>
/// <summary>
? ? /// Action系統(tǒng)泛型委托
? ? /// 和Func相比,Action委托沒有參數威彰,所以Action委托接收的是一個沒有返回值的方法
? ? /// </summary>
? ? class ActionDenlegateDemo
? ? {
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? Action<string> action = (name) => Console.WriteLine($"歡迎參加【 { name}】的活動");
? ? ? ? ? ? action("發(fā)呆");
? ? ? ? }
? ? }
Action委托與Func系列類似出牧,有若干個重載方法,可以接收0-4個參數歇盼,且返回值為void類型的方法
結論:泛型委托作為方法參數舔痕,實際上傳遞的是一個具體的方法或者一個Lambda表達式(多態(tài)的一種表現)