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

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

第 99 講:C# 3 之查詢表達(dá)式(三):where 關(guān)鍵字

2022-04-02 09:53 作者:SunnieShine  | 我要投稿

今天我們要講一個(gè)新的關(guān)鍵字:where。它用來(lái)篩選,可以得到只滿足條件的序列。

Part 1 引例

我們還是使用之前的學(xué)生的序列來(lái)說(shuō)明用法。

假設(shè)我要獲取這些學(xué)生里成年了的人。我不管它們生活的那個(gè)異世界是怎么規(guī)定和計(jì)算年齡的,我們假設(shè)把傳入的第三個(gè)參數(shù)(假設(shè)叫它 Age 屬性)當(dāng)成年齡數(shù)值,然后獲取出所有年齡都大于 18 歲的。

我們之前的關(guān)鍵字都無(wú)法做到,因?yàn)樗鼈兌疾痪哂泻Y選功能。今天我們要介紹的 where 關(guān)鍵字就表示篩選。用法很簡(jiǎn)單,當(dāng)成類似 let 從句那樣,插入到中間當(dāng)成篩選就可以了。

我們使用 where student.Age >= 18 來(lái)計(jì)算和篩選對(duì)象。和之前一樣,我們將 from 后的變量當(dāng)成迭代變量,然后 where 就好比一個(gè) if 條件一樣。所以這個(gè)語(yǔ)句等價(jià)的 foreach 循環(huán)的代碼是這樣的:

很簡(jiǎn)單,對(duì)吧。這就是 where 從句的用法。講完了。

Part 2 where 從句也可以多次使用

C# 的查詢表達(dá)式靈活就靈活在,它可以隨便用而不去考慮底層是怎么去實(shí)現(xiàn)的。

如果你用熟練了的話,你就可以寫出這么長(zhǎng)的查詢表達(dá)式。我們挨個(gè)來(lái)分析一下。

from student in students 表示在迭代 students 集合,然后每一個(gè)元素我們用 student 臨時(shí)表示一下。它類似 foreach 循環(huán)的迭代變量;let age = student.Age 在定義臨時(shí)變量,表示 age 是這個(gè)學(xué)生的年齡信息,用臨時(shí)變量表達(dá)起來(lái);where age >= 18 表示獲取年齡大于等于 18 歲的;let total = student.Chinese + student.English + student.Math 表示計(jì)算這個(gè)學(xué)生的總成績(jī);let average = total / 3.0 表示計(jì)算這個(gè)總分除以 3 的結(jié)果,即平均分;where average >= 60 又是一次篩選,表示學(xué)生的平均分是否大于等于 60;let name = student.Name 表示臨時(shí)變量的定義,得到這個(gè)學(xué)生的名稱;最后的 select name 表示獲取這個(gè)名字作為迭代結(jié)果。

因此,整個(gè)表達(dá)式可以等價(jià)于下面這個(gè) foreach 循環(huán):

是的。let 等價(jià)于一個(gè)變量的定義,where 則直接改成 if 即可。注意兩次 where 從句,先出現(xiàn)的是外層的 if,而出現(xiàn)的則是內(nèi)層的 if。

如果你覺(jué)得大括號(hào)導(dǎo)致的層次級(jí)別太多,你可以取反一下邏輯:

我們直接取反 if 條件,然后直接把后面的代碼減少一次縮進(jìn),再把原來(lái)直接跟在 if 后的執(zhí)行語(yǔ)句改成 continue; 即可。順帶一說(shuō),這也是編程的時(shí)候最習(xí)慣的書寫模式了。我們總是將每次得到的、不滿足條件的對(duì)象通過(guò) continue 語(yǔ)句直接跳過(guò)計(jì)算,代碼可以少一些縮進(jìn),在代碼效率保證了的前提下還減少了縮進(jìn),增強(qiáng)了可讀性。

另外,從這樣的 foreach 循環(huán)的等價(jià)代碼理解可以看出,多次 where 從句篩選出來(lái)的結(jié)果是必須對(duì)這些給出的條件全部都滿足的迭代對(duì)象。

Part 3 緊挨著的 where 從句

剛才我們說(shuō)到一個(gè)結(jié)論。where 從句表示一種篩選過(guò)程,當(dāng)條件滿足的時(shí)候,這樣的對(duì)象才可能被迭代返回出來(lái)。如果多次條件篩選的話,那就相當(dāng)于是 && 處理一樣的效果。

比如下面這樣的代碼:

我省去了一些 let 從句,實(shí)際代碼和原來(lái)的邏輯是一樣的,都是“獲取所有成年并且及格的學(xué)生的名字”。不過(guò),這次我們連著使用了兩次 where 從句。這樣其實(shí)是不好的。因?yàn)閮蓚€(gè) where 條件挨著就意味著代碼是這樣的:

請(qǐng)注意兩個(gè)嵌套的 if。如果 if 出現(xiàn)嵌套,我們就可以認(rèn)為,兩個(gè) if 可以用 && 連起來(lái)。因?yàn)閮蓚€(gè) if 里除了條件判斷以外,沒(méi)有別的執(zhí)行代碼。因此,我們合并到一起判斷,也是一樣的效果:

因此,對(duì)應(yīng)的 where 從句也可以這么做。我們將緊挨著的兩個(gè)甚至更多的 where 從句里面的條件全部使用 && 連起來(lái),然后直接寫成一個(gè) where 從句,即可完成簡(jiǎn)化:

當(dāng)然,如果你不考慮性能的話,其實(shí)寫成原來(lái)的寫法也沒(méi)啥問(wèn)題,兩種寫法執(zhí)行出來(lái)的結(jié)果是一致的,只是性能上有點(diǎn)區(qū)別罷了。

但請(qǐng)注意,連續(xù)出現(xiàn)的 where&& 的邏輯,而不是 || 的邏輯。你不能把兩個(gè)應(yīng)該用 || 連起來(lái)的條件拆解為兩個(gè)連續(xù)的 where 從句表達(dá)出來(lái),也不能將兩個(gè)連續(xù)的 where 從句給的條件用 || 連起來(lái)。初學(xué)這里的時(shí)候經(jīng)常有同學(xué)會(huì)忘記這一點(diǎn),導(dǎo)致邏輯出現(xiàn)問(wèn)題。

Part 4 不太算是題外話的題外話

4-1 from 從句可以不挨在一起用

我們?cè)谡f(shuō)查詢表達(dá)式的最開(kāi)始的內(nèi)容里就說(shuō)過(guò),from 是可以多次使用的,它就等價(jià)于多層的 foreach 循環(huán)。不過(guò),前面的例子還不夠多,所以我們的想象力限制了 from 的用法。實(shí)際上,from 是可以分開(kāi)用的,也就是說(shuō),有一個(gè) from 從句后,跟上一些別的從句(比如 letwhere 從句什么的)之后,然后再來(lái)一個(gè) from 從句,也是可以的。只不過(guò)之前沒(méi)有 where 從句,所以不太好對(duì)這種情況進(jìn)行舉例說(shuō)明。下面我們來(lái)介紹一種用法來(lái)這么去使用 from

考慮一種情況,我現(xiàn)在想對(duì)整個(gè)學(xué)生集合進(jìn)行一男一女的 CP 配對(duì)操作。我們可以這么去寫代碼:

我們從這個(gè)例子里可以看出,這個(gè)例子用到了 from 從句后跟了兩次 let 從句,然后才是新的 from。這也是允許的。它的等價(jià) foreach 代碼也不必多說(shuō):

當(dāng)然,你也可以將兩次挨著的 where 寫到一起,用 && 連接起來(lái)。

下面我們來(lái)說(shuō)說(shuō),這些語(yǔ)句都是什么意思。

我們?cè)俅握瞻嵘厦娴牟樵儽磉_(dá)式:

我們要習(xí)慣去看查詢表達(dá)式而不是 foreach 循環(huán)的等價(jià)寫法。如果每次都要自己腦補(bǔ) foreach 循環(huán)然后去反推查詢表達(dá)式的話,學(xué)習(xí)起來(lái)就比較慢,效率就不太高了。

我們首先迭代了 students 序列,我們將每一個(gè)學(xué)生的名字和性別取出來(lái)留著稍后使用。接著我們?cè)俅沃匦碌?students 序列。注意這次我們寫在上面 from 的下方,因此它等價(jià)于的是 foreach 的嵌套。你想想看,where 多次用的話,前面的 where 改成了外層的 if,而后面的 where 則改成了內(nèi)層的 if。所以 from 的話,也是這個(gè)道理。

兩層嵌套的 foreach 循環(huán)一般都是用來(lái)進(jìn)行兩兩組合的,剛好我們這里就需要一男一女組合,所以完全符合我們這里的需求。繼續(xù)往下看,在得到兩位學(xué)生(兩個(gè) students 迭代期間的臨時(shí)變量 student1student2)的性別和名字后,我們需要判斷這兩個(gè)對(duì)象是否需要配對(duì)。因?yàn)槲覀冎恍枰荒幸慌M合,因此我們需要判斷性別和名字兩個(gè)屬性的數(shù)值。

為什么連名字也要判斷呢?因?yàn)閮蓪忧短椎?foreach 循環(huán)都迭代的是相同的序列,那么完全有可能在迭代期間遇到兩個(gè)循環(huán)迭代到同一個(gè)對(duì)象的情況。為了避免程序的 bug,我們必須排除掉這種特殊情況。因此可以在第 8 行的篩選條件里看到 name1 != name2 的判斷。當(dāng)然,一男一女就意味著兩個(gè)人的性別是不一致的,所以 gender1 != gender2 就比較好理解了。

當(dāng)然,如果你想更加巧妙地使用代碼的話,你可以這么去處理性別比較。假設(shè)我們這個(gè)例子里 Gender 是個(gè)枚舉類型,只包含 MaleFemale 兩個(gè)數(shù)值情況的話,那么我們很容易會(huì)認(rèn)為 Male 對(duì)應(yīng)特征數(shù)值 0、Female 對(duì)應(yīng)特征數(shù)值 1(當(dāng)然,你要反過(guò)來(lái)也行)。那么,要想保證兩個(gè)人的性別不一致,那么我們可以使用異或運(yùn)算。異或運(yùn)算恰好保證的就是兩個(gè)數(shù)值一致的時(shí)候?yàn)?0;反而不一致的時(shí)候是 1。因此,gender1 != gender2 也可以寫成 (gender1 ^ gender2) != 0。

呃好像代碼更長(zhǎng)了……我只是說(shuō)有這么個(gè)用法,是這么個(gè)寫法,是這個(gè)意思。

那么,第 9 行的 where 條件又是個(gè)什么情況呢?之所以沒(méi)有內(nèi)聯(lián)到上一個(gè) where 從句里去,是因?yàn)樗枰獑为?dú)說(shuō)明邏輯。反正這么寫和寫在一起也沒(méi)有運(yùn)行上的差別。這個(gè)第 9 行的代碼,其實(shí)是為了保證我們給出的 student1(也就是外層 foreach 循環(huán)的迭代變量)一定是個(gè)男學(xué)生。因?yàn)榍耙粋€(gè) where 從句(第 8 行)判斷了兩個(gè)學(xué)生不同性別,因此 student1 保證了是男學(xué)生的話,那么 student2 就肯定是女學(xué)生了。這樣我們就可以大大方方在第 10 行的 select 語(yǔ)句里直接指定 MaleFemale 屬性到匿名類型的初始化器里去了。這就是為什么需要額外判斷一下 student1 是不是男性的原因——為了保證一男一女表達(dá)出來(lái)的時(shí)候,先給的 student1 一定是男生,而后給的 student2 一定是女生。

下面請(qǐng)你自己思考一個(gè)問(wèn)題。這樣篩選會(huì)不會(huì)漏掉組合的情況?答案自己想哈,我就不給出解釋了。

4-2 巧用匿名類型簡(jiǎn)化多次定義的 let 從句

例如上面這樣的定義,因?yàn)槲覀儽仨毰袛?NameGender 屬性,因此我們需要用四次 let 從句來(lái)獲取數(shù)值。這樣定義是沒(méi)有問(wèn)題,但是顯然多次定義可以簡(jiǎn)化一下。

我們可以巧妙利用匿名類型來(lái)完成這個(gè)任務(wù)。我們將同一個(gè)對(duì)象的定義過(guò)程放在一個(gè)匿名類型的初始化器里賦值,然后賦值給一個(gè)變量就行了:

我們注意一下修改的地方。我們刪除了賦值過(guò)程,取而代之的是新的賦值過(guò)程。注意賦值的對(duì)象發(fā)生了變化:原來(lái)是屬性的賦值,現(xiàn)在是匿名類型的賦值。這樣的賦值我們只需要寫兩次 let 從句。這樣可以定義和賦值到同一個(gè)變量里去。接著,我們判斷名字和性別是否都不同,它被改成了 pair1pair2 兩個(gè)匿名類型之間的屬性的比較。最后我們的 where 要保證第一個(gè)對(duì)象必須是男性,所以現(xiàn)在我們也需要同步地改變寫法,改用 pair1 來(lái)比較。

注意改變后的判斷語(yǔ)句可能會(huì)變得更長(zhǎng)。這也是沒(méi)辦法的事情。另外,結(jié)合之前我們學(xué)了匿名類型的語(yǔ)法的知識(shí)點(diǎn),我這里留一個(gè)問(wèn)題希望各位思考一下。

請(qǐng)問(wèn),改寫的代碼 where pair1.Name != pair2.Name && pair1.Gender != pair2.Gender(第 11 行)能否寫成 !pair1.Equals(pair2)pair1 != pair2?請(qǐng)說(shuō)明理由。

Part 5 總結(jié)

總的來(lái)說(shuō),我們介紹了 where 的用法,它表示篩選條件。多個(gè)挨著的 where 可以合并到一起,用 && 連起來(lái)。

下面我們將介紹一個(gè)新的從句:orderby 從句。


第 99 講:C# 3 之查詢表達(dá)式(三):where 關(guān)鍵字的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
皮山县| 闵行区| 清徐县| 利川市| 邓州市| 中方县| 和政县| 蒙城县| 会理县| 黑河市| 剑河县| 上林县| 八宿县| 连山| 长丰县| 中方县| 类乌齐县| 新蔡县| 布尔津县| 和田县| 化隆| 河池市| 安徽省| 襄汾县| 垣曲县| 仁布县| 北安市| 海丰县| 谢通门县| 安徽省| 富顺县| 延庆县| 尚志市| 武隆县| 嘉禾县| 江城| 颍上县| 内江市| 菏泽市| 纳雍县| 枣阳市|