程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> [C# 3.0 入門] [第一章 Lambda表達式] 第二節:Lambda表達式帶來了什麼

[C# 3.0 入門] [第一章 Lambda表達式] 第二節:Lambda表達式帶來了什麼

編輯:關於C#

本次的內容,主要是針對已經學習過C# 2.0的程序員讀者的,前提是已經知道什麼是匿名方法。如果還不清楚,請先閱讀“連載:C# 2.0入門”(這篇會在今後翻譯)。

好的,現在進入正題。

Lambda表達式(λ表達式),用一句話來解釋,(不算很嚴謹)就是使匿名方法文字上更短的語法。雖然這樣說,單“僅僅是文字上的變化,源代碼的性質沒有變”這樣的想法也是一種誤解。規模變化了,其性質也會變化。例如,實驗室的燒杯中產生的現象,不一定會在大型的工廠裡產生。同樣的道理也適用於源代碼。

那麼,就體驗一下Lambda表達式吧。

以下,使用具體的code來說明一下,不是實際工程中的代碼,而是實際代碼使用C# 2.0重寫的。

前一陣子筆者實際寫的code中,有一個菜單,能夠選擇的下拉菜單。菜單項是下面這樣定義的:

1public delegate bool SimpleMenuAction();
2
3public class  MenuItemA // 菜單項
4{
5  public readonly string Name; // 名字
6  public readonly SimpleMenuAction Action; //執行內容
7
8  public MenuItemA(string name, SimpleMenuAction action)
9  {
10    Name = name;
11    Action = action;
12  }
13}
14

List 1 菜單項的定義

與之相對應,以下是菜單項的數組。

1private static MenuItemA[] Menu Items1 =
2  {
3    new MenuItemA("選擇項1", 執行方法),
4    new MenuItemA("選擇項2", 執行方法),
5    new MenuItemA("選擇項3", 執行方法),
6  };
7

List 2 菜單項目數組

實際上,當時認為這樣就足夠了,誰知中途又被要求加入一種菜單項,這種菜單項在19點以後才可以看到。如果只有這一個的話,用if語句括起來判斷一下例外條件就能夠處理,可是要求是2個,而且還可能增加。於是,就想在這個表中添加條件語句。

最simple的解決方案,應該就是在MenuItem類裡,保存“幾點以後有效”的“幾點”的整數值。

首先在MenuItemA類中,加上保存時間的整數字段“FromHour”。

1public class MenuItemB
2{
3  public readonly string Name;
4  public readonly SimpleMenuAction Action;
5  public readonly int FromHour;
6
7  public MenuItemB(string name, SimpleMenuAction action, int fromHour)
8  {
9    Name = name;
10    Action = action;
11    FromHour = fromHour;
12  }
13}
14

List 3 加上時間字段的菜單項定義

菜單項數組也改寫成以下:

1private static MenuItemB[] MenuItems2 =
2  {
3    new MenuItemB("選擇項1", 執行方法, 0),
4    new MenuItemB("選擇項2", 執行方法, 0),
5    new MenuItemB("選擇項3", 執行方法, 0),
6    new MenuItemB("選擇項4", 執行方法, 19),
7  };
8

List 4 對List 3的菜單項進行修正

這樣,需要的信息都能夠包含在數組裡了。

構建菜單的方法是,通過檢查被選擇的菜單對象的FromHour的值,如果與現在時間相比小,就把該菜單項顯示出來。

這麼看來,這個code如果按照YAGNI*的原則來看的話就比較完善了,這樣的代碼也屬於良品了。

* YAGNI是“You Aren't Going to Need It.”的簡寫,意思是:或許是必要的功能實際上並不必要的可能性非常高。一句話,為未知的未來而事先准備的代碼,基本上是沒用的。這樣的教訓很多。

但是,這個代碼來應對需求變更的要求,恐怕還太脆弱。例如,條件如果從19點改為19點半,就沒法辦了。或者要求設置個結束時間,或者是個時間段的話,或是根據星期幾而變動,這種要求實在是太多了。

琢磨了一下要求,加入能夠指定條件的代碼,修正後如下:

1public delegate bool SimpleMenuAvailability();
2
3public class MenuItemC
4{
5  public readonly string Name;
6  public readonly SimpleMenuAction Action;
7  // 判斷現在是否是有效菜單項
8  public readonly SimpleMenuAvailability IsAvailable;
9
10  public MenuItemC(string name, SimpleMenuAction action, SimpleMenuAvailability isAvailable)
11  {
12    Name = name;
13    Action = action;
14    IsAvailable = isAvailable;
15  }
16}
17

List5 加上條件的菜單定義

如果使用匿名方法,數組就要改寫成如下:

Menu

1private static MenuItemC[] MenuItems3 =
2  {
3    new MenuItemC(
4     "選擇1", 執行方法, delegate() { return true; }),
5    new MenuItemC(
6     "選擇2", 執行方法, delegate() { return true; }),
7    new MenuItemC(
8     "選擇3", 執行方法, delegate() { return true; }),
9    new MenuItemC(
10     "選擇4", 執行方法, delegate() { return DateTime.Now.Hour >= 19; } ),
11  };
12

List 6 List 5中對應的菜單項

可是,這樣的代碼如果要為將來可能需要也可能不需要的變化准備的話,將會變得相當臃腫。本質上完全沒有意義的delegate和return顯得非常刺眼,看上去很難理解意圖。這種代碼就是YAGNI原則所說的那種應該避免的代碼的典型例子。

因此,如果使用C# 2.0,這種code應該就不會被采用。筆者雖然屬於那種對匿名方法使用得揮金如土的類型,在這個case上,(用匿名方法)恐怕優勢要小於劣勢。

然而,下面這並不是匿名方法,打眼一看就是較少的文字就能描述的Lambda表達式。下面的代碼,“()=>true”和“()=>DateTime.Now.Hour > 19”,一看就是Lambda表達式的樣子。

1private static MenuItemC[] MenuItems4 =
2  {
3    new MenuItemC("選擇項1", 執行方法, ()=>true),
4    new MenuItemC("選擇項2", 執行方法, ()=>true),
5    new MenuItemC("選擇項3", 執行方法, ()=>true),
6    new MenuItemC("選擇項4", 執行方法, ()=>DateTime.Now.Hour >= 19),
7  };
8

List 7 對List 6改用Lambda表達式後

說實話,code寫成這樣應該可以通過了。雖然違反了YAGNI的原則,但在不損害code的可理解性的范圍內,對於未知修改來說也是上了保險了。

事實上這個保險也確實起作用。很快,菜單的有效時間從“19點以後”變成“19點後22點前”。來吧,數組做如下修正:

1private static MenuItemC[] MenuItems5 =
2  {
3    new MenuItemC("選擇項1", 執行方法, ()=>true),
4    new MenuItemC("選擇項2", 執行方法, ()=>true),
5    new MenuItemC("選擇項3", 執行方法, ()=>true),
6    new MenuItemC("選擇項4", 執行方法,
7            ()=>DateTime.Now.Hour >= 19 && DateTime.Now.Hour < 22),
8  };
9

List 8 List 7中第四個菜單項的修改

這個變更,只用改寫一個Lambda表達式這樣的局部變更就能搞定,一瞬間的事。但是,如果采用最初的List 4的code,菜單項類還要加上結束時間,菜單的構建方法中還要加上判斷,相當的費事。然而,不僅如此,如果不是Lambda表達式,而是使用匿名方法的前提下,或許這種費事的方法也會得到采用。總之,匿名方法與Lambda表達式的長度上的差別對code會有質的影響。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved