[深入学习C#]匿名函数、委托和Lambda表达式
轉載自詩人江湖老,原文地址
匿名函數(Anonymous Function)是表示“內聯”方法定義的表達式。匿名函數本身及其內部沒有值或者類型,但是可以轉換為兼容的委托或者表達式樹類型(了解詳情)。匿名函數轉換的計算取決于轉換的目標類型:如果是委托類型,則轉換計算為引用匿名函數所定義的方法的委托;如果是表達式樹類型,則轉換將計算以對象結構形式表示方法結構的表達式樹。
匿名函數有兩種語法風格:Lambda表達式(lambda-expression)和匿名方法表達式(anonymous-method-expression)。在幾乎所有的情況下,Lambda表達式都比匿名方法表達式更為簡介具有表現力。但現在C#語言中仍保留了后者,為了向后兼容。
Lambda表達式:
async可選 (匿名的函數簽名)=> (匿名的函數體)
匿名方法表達式:
async可選 delegate (顯式的匿名函數簽名) 可選{代碼塊}
其中匿名的函數簽名可以包括兩種,一種是隱式的匿名函數簽名另一種是顯式的匿名函數簽名:
隱式的函數簽名:(p)、(p1,p1)
顯式的函數簽名:(int p)、(int p1,int p2)、(ref int p1,out int p2)
匿名的函數體可以是表達式或者代碼塊。
從上面我們可以看出,Lambda表達式的參數形式可以顯式或者隱式類型化。在顯式類型化參數列表中,每個參數的類型是顯式聲明的,在隱式類型化參數列表中,參數的類型是從匿名函數出現的上下文中推斷出來的。
當Lambda表達式只有一個具有隱式類型化參數的時候,參數列表可以省略圓括號,也就是說:
(參數) => 表達式
可以簡寫為
參數 => 表達式
一些匿名函數的示例
x => x + 1 //隱式的類型化,函數體為表達式
x => {return x + 1;} //隱式的類型化,函數體為代碼塊
(int x) => x + 1 //顯式的類型化,函數體為表達式
(int x) => {return x + 1;} //顯式的類型化,函數體為代碼塊
(x , y) => x * y //多參數
() => Console.WriteLine() //無參數
async (t1 , t2) => await t1 + await t2 //異步
delegate (int x) {return x + 1;} //匿名函數方法表達式
delegate {return 1 + 1;} //參數列表省略
Lambda表達式和匿名方法表達式的區別:
● 當沒有參數的時候,匿名方法表達式允許完全省略參數列表,從而可以轉換為具有任意值參數列表的委托類型,Lambda表達式則不能省略參數列表的圓括號()。
● Lambda表達式允許省略和推斷類型參數,而匿名方法表達式要求顯式聲明參數類型。
● Lambda表達式主體可以為表達式或者代碼塊,而匿名方法表達式的主體必須為代碼塊。
● 只有Lambda表達式可以兼容到表達式樹類型。
委托
一個委托是一個指向一個方法的引用,或者說,一個委托的實例就是一個指向某個方法的對象,這是一個簡單卻十分強大的概念。
C#中的委托是用來處理在其他語言中(如C++、Pascal等)需要用函數指針來處理的情況。不過與C++不同的是:委托是完全面向對象的;C++指針僅僅指向成員函數,而委托同時封裝了對象的實例和方法;委托是完全類型安全的,只有當函數的簽名與委托的簽名匹配的時候,委托才可以指向該方法,當委托沒有合法的指向方法的時候不能被調用。
一些關于委托的知識點:
1.委托是類型安全的
委托類型的返回類型必須為void或者輸出安全,委托類型的所有形參類型都必須是輸入安全的。
2.委托類型是名稱等效,不是結構等效
也就是說,對于兩個委托類型,即使它們具有相同的參數列表和返回類型,它們仍將被視為兩個不同的委托類型。
例如:
delegate int A(int x);
delegate int B(int x);
A和B是兩個不同的委托。
但是,兩個結構一樣的委托,它們的實例可以指向同一個方法。
3.委托的調用列表(多播委托)
委托實例所封裝的方法集合稱為調用列表。
當我們從某個方法創建一個委托實例的時候,該實例將封裝此方法,該實例中的調用列表包含一個“入口點”。當我們組合多個非空的委托實例的時候,它們的調用列表將連接在一起形成一個新的調用列表,新的調用列表中包含了多個“入口點”。
委托的組合是使用二元運算符 + 和 += 來進行的,同樣可以使用 - 和 -= 來進行組合的移除。
下面的示例演示多個委托的實例化及其相應的調用列表:
實例化cd1和cd2的時候,它們分別封裝一個方。實例化cd3的時候,它調用的列表有兩個方法M1和M2,而且順序與此相同。cd4的調用列表中依次包含M1、M2、M1。最后,cd5的調用列表中依次包含M2、M1、M1、M2。
4.委托的調用
當調用一個委托實例的時候,將按照調用列表的順序依次調用列表中的各個方法,當在調用期間發生異常,調用列表中排在后面的任何方法將不會被調用。
Lambda表達式
自從C#3.0開始,就可以使用一種新語法把實現代碼賦予委托:Lambda表達式。只要有委托參數類型的地方,就可以使用Lambda表達式。使用匿名方法的地方可以使用Lambda表達式來代替,例如:
Func< string,string > = delagate(string para) {para += "Hello World!";return param; }可以寫成 Func< string,string > = para=> {para +="Hello World!";return para; } Lambda表達式運算符”=>”的左邊列出了需要的參數,右邊定義了賦予Lambda變量的方法的代碼實現。
我們注意到,無論何時,只要我們需要引入匿名方法,我們都需要在前面加上delegate關鍵字,而且參數列表都需要類型化。Lambda表達式提供了一種更為簡潔和自然的語法,而且在C#更多高級的方面中都涉及廣泛。簡而言之,我們應該用Lambda表達式來替代匿名方法。
例如:
添加鏈接描述
總結
以上是生活随笔為你收集整理的[深入学习C#]匿名函数、委托和Lambda表达式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 精通ASP.NET MVC ——辅助器方
- 下一篇: oracle gets/exec 单位,