不能不說的C#特性-匿名方法和Lambda表達式

作者: 橫刀天笑  來源: 博客園  發布時間: 2008-09-23 13:00  閱讀: 19348 次  推薦: 11   原文鏈接   [收藏]  

系列文章導航:

走進Linq--Linq橫空出世篇

走進Linq-輝煌的背后

走進Linq-Linq大觀園

不能不說的C#特性-對象集合初始化器

不能不說的C#特性-匿名類型與隱式類型局部變量

不能不說的C#特性-擴展方法

不能不說的C#特性-匿名方法和Lambda表達式

不能不說的C#特性-迭代器(上)及一些研究過程中的副產品

不能不說的C#特性-迭代器(下),yield以及流的延遲計算

走進Linq-Linq to Objects(上)基礎篇

走進Linq-Linq to Objects(下)實例篇

走進Linq-Linq to SQL感性認識篇

走進Linq-Linq to SQL How do I(1)

走進Linq-Linq to SQL How do I(2)

走進Linq-Linq to SQL How do I(3)

走進Linq-How do I(4)拾遺補零篇第一節

走進Linq-Linq to SQL源代碼賞析 Table的獲取過程

走進Linq-Linq to SQL源代碼賞析之Provider的初始化

走進Linq-Linq to SQL源代碼賞析,通過Linq to SQL看Linq

 

在我們程序中,經常有這樣一些需求:

1. 需要一個臨時方法,這個方法只會使用一次,或者使用的很少。

2. 這個方法的方法體很短,以至于比方法聲明都短,寫起來實在沒勁(我將其稱之為“一句話方法”)。

沒辦法,這樣的方法寫起來真是吃力不討好,比如一些按鈕事件處理中,有些按鈕點擊就是彈出一個對話框,或者調用一下別的什么方法。比如下面的代碼:

this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
private void btnRefresh_Click(object sender, EventArgs e)
{
    BindData();
}

這個”Refresh”按鈕就是做一下調用一下BindData()數據綁定的方法,為此我們不得不寫一個新方法。好了,C# 2.0為我們提供了匿名方法:

this.btnRefresh.Click += delegate(object sender, EventArgs e) { BindData(); };

沒勁的代碼沒了。想知道這種寫法的幕后黑手么?

其實編譯器還是在我們的后面干了一件齷齪的事情:它為我們產生了一個新的方法,它只是表面上為我們節省了代碼。

privatevoidb__0(object sender, EventArgs e)
{
    this.BindData();
}

看看這個編譯器產生的方法的名稱:

b_0,Test是這個匿名方法所放置的地方(因為這個按鈕的時間我是放在一個Test方法里的) 還有一點需要注意的是,如果這個匿名方法是在實例方法里使用,那么編譯器為我們生成的幕后方法也是實例方法,否則就是靜態方法了。

是不是覺得匿名方法這東西很不錯,減少了很多代碼阿,但是匿名方法的使用還并不人性化,什么是人性化呢?比如你可以用自然的語言將程序代碼讀出來,這樣才算人性化了.在.net 2.0中System.Collections.Generic命名空間下List里有一些新增的方法。比如Find,如果使用匿名方法我們如何調用呢:

books.Find(delegate(Book book){return book.Price < 50;});

代碼是很簡單,但是卻無法朗讀出來,來看看Lambda表達式的寫法:

books.Find(book=>book.Price<50);這個Lambda表達式就可以這樣閱讀出來了:給你一本書,如果它的價格小于50則返回true。

好了,那我們就走進Lambda表達式吧:

將使用了Lambda表達式的程序集反編譯后,我們發現,它實際上和匿名方法沒有什么不同。Lambda的輸入參數就對應著delegate括號里面的參數,由于Lambda表達式可以推斷參數的類型,所以這里的參數無需聲明。

Lambda操作符讀作”Goes to”,它后面緊跟著表達式或者是語句塊(這點和匿名方法也不同,匿名方法只能使用語句塊而不能使用表達式),下面我就用實例來說明一下有那些類型的Lambda表達式:

//x的類型省略了,編譯器可以根據上下文推斷出來,后面跟著的是表達式

//x的類型省略了,編譯器可以根據上下文推斷出來,后面跟著的是表達式
x => x+1
deleage(int x){return x+1;}
//后面跟著的是語句塊
x=>{return x+1;}
delegate(int x){return x+1;}
//輸入參數也可以帶類型,帶類型后別忘記小括號哦
(int x) => x+1
delegate(int x){return x+1;}
//也可以多個輸入參數,逗號分隔,別忘記小括號
(x,y) => x+y
delegate(int x,int y){return x+y;}
//無參的也行

() => 1

delegate(){return 1;}

對于Lambda表達式來說她的用法就是如此,但是在Lambda背后卻有很多的故事和玄機。用Lambda表達式可以構建表達式樹,而表達式樹對于Linq來說就像樹根對于樹一樣重要。在這里就不討論表達式樹的問題了,這個東西也不是三言兩語能夠說清楚的,等待時機成熟的時候我們再來進一步討論。

Lambda表達式更多閱讀

Lambda實際上源遠流長,我們現在使用的機器都是馮-諾依曼體系的,屬于圖靈機,在那之前還有一種稱作λ演算的理論,但是圖靈機由于先被實現出來,所以大行其道,λ演算后來成就了函數式編程語言特別是Lisp,在函數式編程語言里函數是第一等元素,函數的參數,函數的返回值都是函數,程序沒有變量,函數嵌套函數。而且函數式編程語言一直存在于象牙塔中,所以在工業界并沒有得到通用,不過近年來工業界比較喜歡“復古”風格,所以函數式編程語言也慢慢的走上了歷史的舞臺。函數式編程能解決一些命令式編程難以解決的問題(或者解決起來非常麻煩)。C#要做到函數風格編程怎么辦?靠原來的方法定義的方式肯定是不可行的,2.0的匿名方法從某種程序上來說解決了這個問題,但還是不夠,3.0里的Lambda終于很好的解決了,一個Lambda就是一個delegate,一個delegate指向一個方法,現在我們使用Lambda也能簡單的將方法作為參數傳遞了,還可以層層嵌套,都是很簡單的事情了。

11
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()