Lambda表達式

Lambda表達式

.NET 3.x新特性之Lambda表達式

lambda 表達式格式爲:
(參數列表) => 表達式或者語句塊
分爲三個步驟
1、(參數列表):
2、=>符號可以理解爲從
3、表達式或者語句塊

可以有多個參數,一個參數,或者無參數。參數類型可以隱失或者顯示。例如:
(x,y) => x * y    //多參數,隱式類型=>表達式
x => x * 10    //單參數,隱式類型=>表達式
x => {return x * 10;}   //單參數,隱失類型=>語句塊
(int x) => x * 10   //單參數,顯示類型=>表達式
(int x) => {return x * 10} //單參數,顯示類型=>語句塊
() => Console.WriteLing() //無參數

 

Lambda表達式其實是一個委託類型實例,編譯器會根據參數的類型建立一個同類型的同參數的委託:
比如
x => x * 10 
相當於是下面一個委託類型的實例
delegate int MyDeg(int i);//這個是由編譯器根據推斷出的類型而建立的
只不過這些工作由編譯器幫我們做了

 

Lambda 表達式格式要點
- Lambda表達式的參數類型可以忽略,因爲可以根據使用的上下文進行推斷。
- Lambda表達式的主體(body)可以是表達式,也可以是語句塊。
- Lambda表達式傳入的實參將參與類型推斷,以及方法重載辨析。
- Lambda表達式和表達式體可以被轉換爲表達式樹。

 

Lambda 表達式與委託類型
Lambda 表達式L可以被轉換爲委託類型D,需要滿足以下條件:
- L和D擁有相同的參數個數。
- L的參數類型要與D的的參數類型相同。注意隱式類型要參與類型辨析。
- D的返回類型與L相同,無論L是表達式,還是語句塊。

下面我們來看一下編譯器到底都做了些什麼?
比如在程序中有下面Lambda表達式:
delegate bool Mydelegate(string s);
class jh
{
    public static Process(Mydelegate myd)
        { 
            myd("wo shi jhxz");
        }
}
jh.Process(s => s.Indexof("jhxz") > 0) //Process方法接受一個Mydelegate的委託

編譯其實有Lambda表達式那條語句編譯爲以下這樣的代碼:
Mydelegate md=new Mydelegate(IsValidXXXX);//編譯器生成
jh.Process(md1)
public static bool IsValidXXXX(string s)//編譯器生成
{
  return s.Indexof("jhxz") > 0;
}

 

 

體驗:
1.準備測試數據
static int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
static string[] strings = new string[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
class Person {
public string Name;
public int Level;
}
static Person[] persons = new Person[] {
new Person {Name="Matt", Level=3},
new Person {Name="Luca", Level=3},
new Person {Name="Jomo", Level=5},
new Person {Name="Dinesh", Level=3},
new Person {Name="Charlie", Level=3},
new Person {Name="Mads", Level=3},
new Person {Name="Anders", Level=9}
};
2.過濾數據
public static void Sample1() {
// use Where() to filter out elements matching a particular condition       
        IEnumerable<int> fnums = numbers.Where(n => n < 5);
Console.WriteLine("Numbers < 5");
foreach(int x in fnums) {
Console.WriteLine(x);
}
}
3.匹配首個字母
public static void Sample2() {
// use First() to find the one element matching a particular condition 
        string v = strings.First(s => s[0] == 'o');
Console.WriteLine("string starting with 'o': {0}", v);
}
4.根據numbers排序
public static void Sample3() {
// use Select() to convert each element into a new value
        IEnumerable<string> snums = numbers.Select(n => strings[n]);
Console.WriteLine("Numbers");
foreach(string s in snums) {
Console.WriteLine(s);
}
}
5.匿名類型,注意var關鍵字
public static void Sample4()
{
// use Anonymous Type constructors to construct multi-valued results on the fly
        var q = strings.Select(s => new {Head = s.Substring(0,1), Tail = s.Substring(1)});
foreach(var p in q) {
Console.WriteLine("Head = {0}, Tail = {1}", p.Head, p.Tail);
}
}
6.聯合查詢(即使用兩個以上的查詢條件)
public static void Sample5() {
// Combine Select() and Where() to make a complete query
        var q = numbers.Where(n => n < 5).Select(n => strings[n]);
Console.WriteLine("Numbers < 5");
foreach(var x in q) {
Console.WriteLine(x);
}
}
7.使用ToList方法
public static void Sample6() {
// Sequence operators form first-class queries are not executed until you enumerate them.
        int i = 0;
var q = numbers.Select(n => ++i);
// Note, the local variable 'i' is not incremented until each element is evaluated (as a side-effect).
        foreach(var v in q) {
Console.WriteLine("v = {0}, i = {1}", v, i);
}
Console.WriteLine();
// Methods like ToList() cause the query to be executed immediately, caching the results
        int i2 = 0;
var q2 = numbers.Select(n => ++i2).ToList();
// The local variable i2 has already been fully incremented before we iterate the results
        foreach(var v in q2) {
Console.WriteLine("v = {0}, i2 = {1}", v, i2);
}
}
8.分組查詢
public static void Sample7() {
// use GroupBy() to construct group partitions out of similar elements
        var q = strings.GroupBy(s => s[0]); // <- group by first character of each string

foreach(var g in q) {
Console.WriteLine("Group: {0}", g.Key);
foreach(string v in g) {
Console.WriteLine("\tValue: {0}", v);
}
}
}
9.統計聚合
public static void Sample8() {
// use GroupBy() and aggregates such as Count(), Min(), Max(), Sum(), Average() to compute values over a partition
        var q = strings.GroupBy(s => s[0]).Select(g => new {FirstChar = g.Key, Count = g.Count()});
foreach(var v in q) {
Console.WriteLine("There are {0} string(s) starting with the letter {1}", v.Count, v.FirstChar);
}
}
10.排序
// use OrderBy()/OrderByDescending() to give order to your resulting sequence
        var q = strings.OrderBy(s => s); // order the strings by their name

foreach(string s in q) {
Console.WriteLine(s);
}
}
11.二次排序
public static void Sample9a() {
// use ThenBy()/ThenByDescending() to provide additional ordering detail
        var q = persons.OrderBy(p => p.Level).ThenBy(p => p.Name);
foreach(var p in q) {
Console.WriteLine("{0} {1}", p.Level, p.Name);
}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章