最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

探索 C# 10 的拓展 Lambda

2021-09-18 07:34 作者:SunnieShine  | 我要投稿

C# 10 開始擴展 Lambda 表達式。C# 3 誕生 Lambda 表達式,基本夠用。不過極少數(shù)時候不得不需要一些特殊情況的時候,Lambda 表達式就不夠用了。比如

  • 給 Lambda 表達式的參數(shù)和返回值添加特性;

  • 給 Lambda 指定返回值類型,以便直接調(diào)用 Lambda。

為 Lambda 指定參數(shù)和返回值類型

為了明確 Lambda 的參數(shù)和返回值類型,我們發(fā)明了一種新的語法。原本的語法規(guī)則只能指定參數(shù)類型,但返回值類型無法固定。返回值類型直接使用和普通方法的語法一樣的、先類型后參數(shù)表列的方式表示:

比如這樣。返回值是 string 類型。

至于參數(shù)類型的聲明格式,這個是 Lambda 本來的語法,我就不多說了。因為 Lambda 沒有方法名,是即時聲明即時使用的一種語法,所以如果你記不住寫法,可以嘗試在參數(shù)表列前面補充一個方法名,還原成一個完整的方法聲明簽名的模式,來看是不是語法寫對了。

為 Lambda 指定特性

Lambda 在升級寫法之后,還可以為參數(shù)、返回值或 Lambda 方法本身標(biāo)記特性了。下面我們來用法和代碼。

從這個例子我們看到,我們給 () => { } 這個 Lambda 追加了特性 AAttribute,這樣的話,Lambda 則自動對應(yīng)到不返回、無參數(shù)的方法簽名。

請注意,我們直接添加的 [A] 特性語法,這表示將整個 Lambda 表達式底層生成的方法標(biāo)記 A 特性。如果想對參數(shù)標(biāo)記特性的話,需要一對小括號:

我們對 a 這個參數(shù)標(biāo)記 [A] 特性,為了避免和 Lambda 表達式的標(biāo)記方式?jīng)_突,需要一對小括號。

如果標(biāo)記返回值上的話:

一些分析器語法分析的小問題

請注意如下語法:

請問這個寫法有沒有問題?是的,這個寫法是有語法沖突的。C# 6 有 ?[ 這樣的運算符,注意 b ? [A] () => { } 語法,問號后直接跟了一個開中括號,所以會產(chǎn)生語法沖突。因此,我們不得不需要使用小括號才可以允許:

自然簽名

我們約定,把 Lambda 表達式聲明可以推出來的簽名稱為 Lambda 表達式的自然簽名??蓡栴}就在于,如果我們無法知道 Lambda 的參數(shù),就不可能得到它的自然類型。因此,我們給大家五個例子,讓大家明白自然簽名的推斷方式。

應(yīng)該從例子看得出來,前面三個因為無法暗示出參數(shù)類型和返回值類型,我們無法得到明確的自然簽名;但是后面兩個可以。比如 f4 變量的 Lambda:() => 1,因為返回值是 int 類型的字面量,而參數(shù)是空的,所以它自動對應(yīng)無參數(shù)返回 int 類型的 Func<int> 類型;最后一個因為帶有返回值類型 string,因此自動對應(yīng) Func<string>

直接調(diào)用 Lambda

Lambda 表達式以前不支持直接調(diào)用,現(xiàn)在可以用 var 關(guān)鍵字表示其類型了,因此……還是不行 :(

這個主要是因為會增加代碼復(fù)雜度,降低可讀性,以及分析器分析的復(fù)雜度等等,所以 C# 10 里仍然沒有實現(xiàn)這個功能。不過現(xiàn)在有了 var 來表達類型,就不必那么復(fù)雜了:

之類的。

Lambda 對 Delegateobject 類型的隱式轉(zhuǎn)換規(guī)則

因為之前說過,Lambda 最終是賦值給一個 Action 或者 Func 這樣的委托類型的,而委托類型默認從 Delegate 類型派生,因此所有的委托對象都可以賦值給 Delegate 類型(多態(tài))。

可是問題在于,我們無法確定它的類型,就無法直接賦值,比如前面的 () => default 語法。下面我們來幾個例子。

第一個例子 1.GetHashCode 和第三個例子 (int x) => x 因為確定了返回值和參數(shù)類型,因此包含自然簽名,可以轉(zhuǎn)換;但是如果使用 x => x 這樣的語法,因為沒有自然簽名,就無法轉(zhuǎn)換。

然后是第二個例子和第一個例子的書寫??赡苣憧粗鴦e扭。這是什么意思呢?因為 GetHashCodeToString 此時是實例方法,需要默認代入一個實例才可參與計算,所以在使用的時候,我們需要優(yōu)先指定實例是什么。比如這里的 1.GetHashCode1 是調(diào)用 GetHashCode 的實例,而 GetHashCode 自身又可以明確確定簽名,所以賦值是可以成功的;不過,2.ToString 就不行了。因為 ToString 調(diào)用的實例是 int 類型(字面量 2int 類型的),但 int 類型的 ToString 方法包含重載,所以無法確定到底是哪個調(diào)用,因此也會出錯。

特別說明一下 GetHashCodeToString 這樣連參數(shù)表列都不帶的書寫方式。這一點 Lambda 里在 C# 5 開始就有。如果調(diào)用的方法(顯式方法名,比如 ToString 這樣帶名字的方法,而不是 Lambda 這種沒名字的方法)的簽名和調(diào)用時候需要的變量(參數(shù))本身給定的簽名一致,就允許直接寫名字:

比如這樣。

Lambda 對重載方法的最優(yōu)選取

有些時候,Lambda 現(xiàn)在可以暗示簽名之后就會出現(xiàn)更多的轉(zhuǎn)換的問題。

比如這樣。Invoke 方法直接有三個重載,分別是 Func<string>、DelegateExpression 類型接收 Lambda 作為參數(shù)??蓡栴}就在于,如果我們直接傳入方法名稱后,就無法確定執(zhí)行的方法的類型了。

C# 3 出現(xiàn) LINQ 的時候,就已經(jīng)開始允許 Lambda 表達式直接賦值給 Expression 類型。Expression 類型表示的是這個表達式自身的語法樹結(jié)構(gòu)。也就是說,C# 3 允許 Lambda 賦值給 Expression 類型,是為了直接把 Lambda 轉(zhuǎn)換成語法樹,方便 LINQ 里的語義轉(zhuǎn)換。

那么,既然三種類型都可接收 Lambda 的話,現(xiàn)在調(diào)用的方法究竟又是如何選擇的呢?很簡單,找匹配即可。為了規(guī)避 C# 3 語義上給定的語法規(guī)則沖突,如果自然簽名類型契合的話,自然是選擇最優(yōu)的;但是如果不契合的話,如果是方法名,就選取 Delegate;如果是 Lambda,就選取 Expression,比如上面這樣的例子。因為 C# 3 的 Expression 賦值 Lambda 是一個已經(jīng)存在的語法,所以不能改變;而 GetInt 方法既可以賦值給 Delegate 類型又可以賦值給 Expression 類型的話,會選擇 Delegate 一邊,因為這也是更合適合理的傳遞參數(shù)的規(guī)則。


探索 C# 10 的拓展 Lambda的評論 (共 條)

分享到微博請遵守國家法律
灵宝市| 宜宾县| 永宁县| 仁布县| 古蔺县| 安吉县| 湖南省| 彭泽县| 烟台市| 荣昌县| 温州市| 崇阳县| 花垣县| 金华市| 连江县| 潍坊市| 神农架林区| 开化县| 浦东新区| 辽中县| 拜泉县| 通化县| 方正县| 苏州市| 江西省| 苏尼特左旗| 商城县| 满城县| 云林县| 习水县| 通化县| 建平县| 嘉禾县| 凤台县| 邯郸市| 宁海县| 河曲县| 渭南市| 阳西县| 红河县| 祁连县|