程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 16.C#初見Lambda表達式及表達式樹(九章9.1-9.3),

16.C#初見Lambda表達式及表達式樹(九章9.1-9.3),

編輯:C#入門知識

16.C#初見Lambda表達式及表達式樹(九章9.1-9.3),


  在說明Lambda相關知識前,我們需要了解Lambda表達式常用於LINQ,那麼我們來聊下LINQ。

  LINQ的基本功能就是創建操作管道,以及這些操作需要的任何狀態。這些操作表示了各種關於數據的邏輯:如何過濾、如何排序以及如何將不同的數據源連接在一起,等等。執行委托只是LINQ的眾多能力之一。為了富有效率地使用數據庫和其他查詢引擎,我們需要以一種不同的方式來表示管道中的各個操作。這種不同的方式就可以使用Lambda表達式來表現。下面分別使用委托(使用匿名函數)和Lambda表達式來作出同樣的事情:返回一個人的到現在一共活了多少天。

 1 class Person
 2 {
 3     public DateTime BirthDay { get; set; }
 4 }
 5 
 6 public delegate int GetLifeDays(Person p);//聲明一個委托類型
 7 static void Main(string[] args)
 8 {
 9     Person p = new Person() { BirthDay = new DateTime(1900, 12, 17) };
10 
11     GetLifeDays gfd = delegate (Person x) { //實例化一個委托
12 return (DateTime.Now - x.BirthDay).Days; 13 }; 14 Console.WriteLine(gfd(p)); 15 16 GetLifeDays gfd1 = (Person x) => { return (DateTime.Now - x.BirthDay).Days; }; 17 Console.WriteLine(gfd1(p)); 18 19 GetLifeDays gfd2 = (Person x) => (DateTime.Now - x.BirthDay).Days; //去除了後面的大括號,“;”為表達式結束,不是Lambda的結束 20 Console.WriteLine(gfd2(p)); 21 22 GetLifeDays gfd3 = (x) => { return (DateTime.Now - x.BirthDay).Days; }; //讓編譯器推斷參數的類型 23 Console.WriteLine(gfd3(p)); 24 25 GetLifeDays gfd4 = (x) => (DateTime.Now - x.BirthDay).Days; //同時省去參數類型和大括號 26 Console.WriteLine(gfd4(p)); 27 28 GetLifeDays gfd5 = x => (DateTime.Now - x.BirthDay).Days; //再進一步,省去參數列表的括號 29 Console.WriteLine(gfd5(p)); 30 31 Console.ReadKey(); 32 }

   上述是單一參數的各種情況,對於有兩個或多個參數的,效果是"一個到到從出生到某一天的相隔天數",某一天肯定是要大於出生那天啦。

 1 public delegate int GetDaysTo(Person p, DateTime d);
 2 static void Main(string[] args)
 3 {
 4     Person p = new Person() { BirthDay = new DateTime(1900, 12, 17) };
 5 
 6     DateTime d = new DateTime(2100, 12, 12);
 7     //使用匿名方法
 8     GetDaysTo gdt = delegate (Person x, DateTime y)
 9     {
10         return (y - x.BirthDay).Days;
11     };
12     Console.WriteLine(gdt(p, d));
13 
14     GetDaysTo gdt1 = (Person x, DateTime y) => { return (y - x.BirthDay).Days; };
15     Console.WriteLine(gdt1(p, d));
16 
17     GetDaysTo gdt2 = (Person x, DateTime y) => (y - x.BirthDay).Days;
18     Console.WriteLine(gdt2(p, d));
19 
20     GetDaysTo gdt3 = (x, y) => (y - x.BirthDay).Days;
21     Console.WriteLine(gdt3(p, d));
22 
23     //GetDaysTo gdt4 = x, y => (y - x.BirthDay).Days; Error
24     //Console.WriteLine(gdt4(p, d));
25 
26     Console.ReadKey();
27 }

  可以看出當參數為兩個或兩個以上時,不能省略參數列表中的括號,那也可以想像在語句兩條或兩條以上時,不能省略大括號。

  下面結合之前的知識,對一個列表使用ambda表達式進行操作。

 1 //使用集合初始化器
 2 List<Person> l = new List<Person> {
 3     new Person { BirthDay=new DateTime(1990,11,11)},
 4     new Person { BirthDay=new DateTime(1890,12,12)},
 5     new Person { BirthDay=new DateTime(1891,12,12)},
 6     new Person { BirthDay=new DateTime(1892,12,12)},
 7     new Person() { BirthDay=new DateTime(1870,12,12)}
 8 };
 9 
10 //找到大於new DateTime(1890,1,1)的人
11 var result0 = l.FindAll(x => x.BirthDay > new DateTime(1890, 1, 1));
12 
13 //按年齡從小到大排序
14 l.Sort((x, y) => x.BirthDay > y.BirthDay ? -1 : 1);
15 foreach (var e in l)
16 {
17     Console.WriteLine((DateTime.Now - e.BirthDay).Days);
18 }
19 
20 //循環打印每個人的出生天數,效果和上面的foreach一樣
21 l.ForEach(x => Console.WriteLine((DateTime.Now - x.BirthDay).Days));
22 
23 //找到BirthDay=new DateTime(1890,12,12)的人
24 var result1 = l.Find(x => x.BirthDay == new DateTime(1890, 12, 12));

  接下來,我們來說下表達式樹,.NET3.5的表達式提供了一種抽象的方式將一些代碼表示成一個對象樹,表達式樹主要用於LINQ。System.Linq.Expressions命名空間包含了代表表達式的各個類,它們都繼承於Expression,一個抽象的主要包含一些靜態工廠方法的類,這些方法用於創建其它表達類的實例。

  Expression類包含兩個屬性:

1 Expression first = Expression.Constant(5);
2 Expression result = Expression.Add(first, first);
3 Console.WriteLine(result);

  斷點對象各屬性

  上圖分別為first對象和result對象的各屬性值。

  • 將表達式樹編譯成委托

  LambdaExpression是從Expression派生的類型之一。泛型類Expression<TDelegate>又是從LambdaExpression中派生。Expression和Expression<TDelegate>區別在於泛型類以靜態類的方法標識了它是什麼各類的表達式,也就是說,它確定了返回類型和參數。很顯然,這是用TDelegate類型參數來表示的,它必須是一個委托類型。LambdaExpression有一個Compile方法能創建恰當類型的委托。Expression<TDelegate>也有一個同名的方法 ,但它靜態類型化返回TDelegate類型的委托。如:

1 Expression first = Expression.Constant(5);
2 Expression result = Expression.Add(first, first);
3 Func<int> add = Expression.Lambda<Func<int>>(result).Compile();
4 Console.WriteLine(add()); //10
  • 將C#Lambda表達式轉換為表達式樹

  Lambda表達式能顯式或隱式地轉換為恰當的委托實例,然而這些並非唯一能進行的轉換,還可以要求編譯器通過你的Lambda表達式構建一個表達式樹,在執行時創建Expression<TDelegate>的一個實例。如

1 Expression<Func<int>> re = () => 5;
2 Func<int> add0 = re.Compile();
3 Console.WriteLine(add0());

   後面的那些內容真心太復雜了,自己實在理解不了,而且日常使用中也沒有使用過,沒有底氣聊這個話題,想深入的朋友可以自己深入去了解,這裡就做罷了吧。

  請斧正。

  1. 上一頁:
  2. 下一頁: