Linq查詢與高級C#編程機(jī)器理論研究基礎(chǔ)
C#委托解決的是對象之間的逆向傳遞問題,其次,委托還有其他的用途(匿名方法、Lambda表達(dá)式、和泛型結(jié)合),涉及到高級編程中(LInq查詢、擴(kuò)展方法)的底層原理。
一、匿名方法、Lambda表達(dá)式
1、匿名方法
概念:一個(gè)只有關(guān)鍵字delegate、方法參數(shù)、方法體,但沒有具體的名稱,這種方法稱為匿名方法
好處:將具體方法和委托直接關(guān)聯(lián)到一起,如果我們基于委托只需要一個(gè)方法的時(shí)候,匿名方法顯得更加簡單
CalculatorDelegate cal2 = delegate (int a, int b)
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? return a - b;
? ? ? ? ? ? ? };
2、Lambda表達(dá)式
C#3.0以后,可以使用Lambda表達(dá)式更加簡練地編寫程序塊。
//將匿名方法使用Lambda表達(dá)式簡化編寫
? ? ? ? ? ? CalculatorDelegate cal3 = (int a, int b) => { return a + b};
//進(jìn)一步簡化:假如方法中只有一行代碼
? ? ? ? ? ? CalculatorDelegate cal4 = (a, b) => a - b;
【1】在Lambda表達(dá)式中,參數(shù)類型可以是明確類型,也可以是推斷類型
【2】如果是推斷類型,則參數(shù)類型可以由編譯根據(jù)上下文自動(dòng)推斷出來
【3】運(yùn)算符=>讀作goes to,運(yùn)算符左邊輸入?yún)?shù)(如果有),右邊是表達(dá)式或語句塊
【4】表達(dá)式兩種方式:
(input args)=>表達(dá)式
(input args)=>{語句1;語句2;語句3……}
【5】Lambda表達(dá)式與匿名方法的比較
(1)Lambda表達(dá)式本身就是匿名方法
(2)Lambda表達(dá)式允許不指明參數(shù)類型、但是匿名方法必須明確
(3)Lambda表達(dá)式允許單一的表達(dá)式或多條語句組成,而匿名方法不允許單一表達(dá)式
例:
public void test()
? ? ? ? {
? ? ? ? ? ? //【1】委托關(guān)聯(lián)獨(dú)立的方法
? ? ? ? ? ? CalculatorDelegate cal1 = Add;
? ? ? ? ? ? //【2】委托關(guān)聯(lián)匿名方法
? ? ? ? ? ? CalculatorDelegate cal2 = delegate (int a, int b)
? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? return a - b;
? ? ? ? ? ? ? };
? ? ? ? ? ? //【3】將匿名方法使用Lambda表達(dá)式簡化編寫
? ? ? ? ? ? CalculatorDelegate cal3 = (int a, int b) => { return a + b};
? ? ? ? ? ? //進(jìn)一步簡化:假如方法中只有一行代碼
? ? ? ? ? ? CalculatorDelegate cal4 = (a, b) => a - b;
? ? ? ? ? ? sayHelloDelegate sayHello = () => "歡迎你";
? ? ? ? ? ? Console.WriteLine("通過匿名方法計(jì)算:20-30="+cal2(20,30));
? ? ? ? }-
? ? ? ? private int Add(int a, int b)
? ? ? ? {
? ? ? ? ? ? return a + b;
? ? ? ? } //根據(jù)委托的使用可以繼續(xù)添加其他方法
? ? ? ? public delegate int CalculatorDelegate(int a, int b);
? ? ? ? public delegate string sayHelloDelegate();
? ? }
二、自定義泛型委托
1、為什么要使用泛型委托?
普通委托在數(shù)據(jù)類型上的限制是非常嚴(yán)格的,無法適應(yīng)需求變化
2、泛型委托定義:本質(zhì)上和泛型方法非常類似,泛型委托關(guān)聯(lián)的時(shí)候,可以是具體方法、匿名方法、Lambda表達(dá)式
/// <summary>
? ? /// 泛型委托
? ? /// </summary>
? ? class GenericDelegate
? ? {
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? //使用泛型委托:具體方法
? ? ? ? ? ? MyGenericDelegate<int> myDelegate1 = Add;
? ? ? ? }
? ? ? ? //根據(jù)委托定義方法
? ? ? ? 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、問題引出:如果使用多個(gè)參數(shù),按照上述方法不得不定義很多這種泛型委托,非常麻煩
三、系統(tǒng)泛型委托
為了方便開發(fā)者,.NET基類庫中針對常用的情況,提供了預(yù)定委托。這些委托使用非常廣泛
兩種方式:一種是有返回值Func<args>,一種是沒有返回值A(chǔ)ction<args>
Action<args>在多線程中用的非常多
Func<args>在linq中用的非常多
Func<args>
/// <summary>
? ? /// 有返回值的系統(tǒng)類型的泛型委托
? ? /// 目的:為了方便開發(fā)者,.NET基類庫中針對常用的情況,提供了預(yù)定委托。這些委托使用非常廣泛
? ? /// </summary>
? ? class FunDelegateDemo
? ? {
? ? ? ? #region Func委托的基本使用
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? //【1】Func關(guān)聯(lián)具體方法
? ? ? ? ? Func<int, int, double> myfunc1= Add1;
? ? ? ? ? ? //【2】Func直接使用Lambda表達(dá)式
? ? ? ? ? ? Func<int, int, double> myFunc = (a, b) => a + b;
? ? ? ? }
? ? ? ? private double Add1(int a, int b)
? ? ? ? {
? ? ? ? ? ? return a + b;
? ? ? ? }
? ? ? ? #endregion
? ? ? ? #region Func委托的重要使用
? ? ? ? //問題:給定一個(gè)數(shù)組,從數(shù)組中指定位置抽取3個(gè)數(shù),求和,求積
? ? ? ? //思考:運(yùn)算的要求不一樣(求和,求積),兩種運(yùn)算可以單獨(dú)作為方法
? ? ? ? ? ? #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委托,將“運(yùn)算”本身作為方法參數(shù)
? ? ? ? ? ? public int Operation(Func<int,int,int> method ,int[] nums,int from,int to? )
? ? ? ? ? ? {
? ? ? ? ? ? int result = nums[from];//把第一個(gè)值作為基數(shù)
? ? ? ? ? ? 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作為方法參數(shù),結(jié)合Lambda表達(dá)式
? ? ? ? ? ? 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委托沒有參數(shù),所以Action委托接收的是一個(gè)沒有返回值的方法
? ? /// </summary>
? ? class ActionDenlegateDemo
? ? {
? ? ? ? public void Test()
? ? ? ? {
? ? ? ? ? ? Action<string> action = (name) => Console.WriteLine($"歡迎參加【 { name}】的活動(dòng)");
? ? ? ? ? ? action("發(fā)呆");
? ? ? ? }
? ? }
Action委托與Func系列類似,有若干個(gè)重載方法,可以接收0-4個(gè)參數(shù),且返回值為void類型的方法
結(jié)論:泛型委托作為方法參數(shù),實(shí)際上傳遞的是一個(gè)具體的方法或者一個(gè)Lambda表達(dá)式(多態(tài)的一種表現(xiàn))