之前總結了委托這個困惑着大多初學者的概念,繼續來學習匿名方法和lambda表達式
(1)我們之前寫了這樣一段代碼
//自定義一個委托 public delegate int Expression(int a, int b); class Program { static void Main(string[] args) { //(2)委托擴展 //Expression ex = Add; //Calculate(ex, 25, 10); Calculate(Add, 25, 10); } static int Add(int a, int b) { return a + b; } static int Divide(int a, int b) { return a / b; } static int subtract(int a, int b) { return a - b; } static int multiply(int a, int b) { return a * b; } static int GetAdd(int a, int b) { return a + b; } static void Calculate(Expression ex, int a, int b) { Console.WriteLine(ex(a, b) + "\n"); } }
我們既然之前說到已經把Calculate封裝起來了,那么這里我們就把Calculate方法看成一個已經封裝好了的方法(這里只是為了舉例,並不是指Calculate方法真的已經完全封裝好了),那么既然Calculate已經不能改了,那么四個加減乘除方法有什么可以優化的地方呢?,我們把a - b,a * b,a / b等等可以寫的計算表達式寫成不同的方法,而且還分別不同命名,這樣做是不是有點過於“浪費”了勒,我們寫這樣四個方法真正要實現的目的就是能讓四個方法傳遞到另一個方法的某一個語句塊中被執行,這段要被傳遞的語句塊有沒有名字其實並不重要,那么這里就要引出一位今天的主人公了,他就是匿名方法,很多人剛接觸這個概念時可能會一頭霧水,而且大多教科書都喜歡把它放在委托的后面講,就會覺得這個東西很神奇,其實匿名方法並沒有那么復雜,不明白只是因為對這個概念生疏而已,或者說是人的慣性思維,我們在初學時都習慣了約定俗成的認為一個方法必須有名字,有參數,有返回值,其實語言的設計者再設計方法(有的語言也叫函數)的初衷就是增加代碼的重用,使代碼更靈活而已,不管是方法還是匿名方法,其本質都是一段執行語句,所以顧名思義,匿名方法就是沒有名字的一方法,那方法是什么,你可以粗暴的理解為方法就是一段可以通過方法名來調用執行語句,那么匿名方法就是一段沒有名字的執行語句,他們都是執行語句。說了這么多我來具體看一下,如何通過匿名方法實現上面的代碼
//自定義一個委托 public delegate int Expression(int a, int b); class Program { static void Main(string[] args) { //(3)匿名方法 Expression add = delegate (int a, int b) { return a + b; }; Expression subtract = delegate (int a, int b) { return a - b; }; Expression multiply = delegate (int a, int b) { return a * b; }; Expression divide = delegate (int a, int b) { return a / b; }; Calculate(add, 10, 25); } //static int Add(int a, int b) //{ // return a + b; //} //static int Divide(int a, int b) //{ // return a / b; //} //static int subtract(int a, int b) //{ // return a - b; //} //static int multiply(int a, int b) //{ // return a * b; //} static void Calculate(Expression ex, int a, int b) { Console.WriteLine(ex(a, b) + "\n"); } }
這里我們直接對Expression委托類型進行賦值,將四個匿名方法賦值給了Expression的實例,這樣我們不必在為每種計算分別寫不同的方法了,這樣寫看上去是不是比之前美觀簡潔了許多,但是實際代碼並沒有減少許多,我們可不可以有什么方法,直接寫一個表達式傳給Calculate方法呢?這里就要引入今天的另一個主角——lambda表達式,說到lambda表達式,你並不要害怕,其實lambda表達式並不是一個全新的概念,它只不過是升級了的匿名方法罷了,很多初學者看到lambda表達式,完全無法想象他與匿名方法,以及委托有什么關系,又會誤認為它是一個全新的概念,其實並不是,它只不過是一段更為簡潔的匿名方法罷了,也可以它只不過是一段更為簡潔的執行語句罷了。下面我們就來通過代碼來對比lambda表達式,匿名方法,以及方法+委托
(1)最原始的一種,定義方法,通過委托傳遞或調用方法
//自定義一個委托 public delegate int Expression(int a, int b); class Program { static void Main(string[] args) { Expression ex = Add; Calculate(ex, 10, 25); //或者直接這樣寫 //Calculate(Add, 10, 25); Console.ReadKey(); } static int Add(int a, int b) { return a + b; } static int Divide(int a, int b) { return a / b; } static int subtract(int a, int b) { return a - b; } static int multiply(int a, int b) { return a * b; } static void Calculate(Expression ex, int a, int b) { Console.WriteLine(ex(a, b) + "\n"); } }
(2)第二種,也就是最上面寫的那種,通過委托傳遞匿名方法
//自定義一個委托 public delegate int Expression(int a, int b); class Program { static void Main(string[] args) { Expression add = delegate (int a, int b) { return a + b; }; Expression subtract = delegate (int a, int b) { return a - b; }; Expression multiply = delegate (int a, int b) { return a * b; }; Expression divide = delegate (int a, int b) { return a / b; }; Calculate(add, 10, 25); } static void Calculate(Expression ex, int a, int b) { Console.WriteLine(ex(a, b) + "\n"); } }
(2)第三種,進一步簡化匿名方法,直接傳遞lambda表達式
public delegate int Expression(int a, int b); class Program { static void Main(string[] args) { Calculate((a, b) => a + b, 10, 25); Calculate((a, b) => a - b, 10, 25); Calculate((a, b) => a * b, 10, 25); Calculate((a, b) => a / b, 10, 25); } static void Calculate(Expression ex, int a, int b) { Console.WriteLine(ex(a, b) + "\n"); } }
可能你對第三部的寫法還是有些不太明白,為什么(a, b) => a + b連參數類型和返回值都沒有了,還是可以編譯和執行,系統是如何知道這個表達式的參數類型和返回值的呢?這里我們在方法Calculate定義的時候第一個參數是Expression類型,所以我們既然已經在定義委托時已經規定了Expression的參數個數,參數類型,以及返回值類型,那么我們在寫lambda表達式就不必在重復定義類型了,所以參數類型與返回值類型不用重復定義,只是需要注意到是參數個數,當lambda表達式只有一個參數時,表達式的”()“括號可以省略,無參和多參括號都不可以省。
這就是從委托到lambda表達式一步步的演化,我們的理解也一步步的加深,其實這就是lambda表達式就是C#這門語言不斷進化的產物,無論它怎樣進化,變得多么簡單,它最終的本質還是逃不過那幾個字:一段可以被傳遞的執行語句