巧用 C#模式匹配,和if-else語句“說拜拜”
當前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
一、if-else語句維護難題知多少![]() (一)破壞程序結(jié)構(gòu)在日常編程過程中,我們常常會使用到 if-else語句,它確實能夠幫助我們實現(xiàn)各種條件判斷下的不同邏輯處理。然而,當代碼中大量使用if-else語句時,就會產(chǎn)生不少問題,其中對程序結(jié)構(gòu)的破壞尤為明顯。 隨著業(yè)務(wù)邏輯的復(fù)雜,if-else語句可能會層層嵌套,就像下面這樣一段簡單模擬的代碼示例:
起初這段代碼用于判斷不同條件時執(zhí)行不同的代碼塊,看著還算清晰??梢坏y試時發(fā)現(xiàn)了新問題,需要調(diào)整邏輯,比如當 condition1和condition3同時滿足時應(yīng)該先執(zhí)行f4,代碼修改后可能就變成了如下模樣:
這還僅僅是比較簡單的邏輯調(diào)整,如果是更為復(fù)雜的業(yè)務(wù)場景,if-else的數(shù)量會遠遠多于上述示例。要是各種condition都是使用flag變量進行標記時,代碼的可讀性將會變得極差,后續(xù)開發(fā)人員去理解代碼意圖就如同在迷宮中找出口一樣困難。而且在維護這樣的代碼時,每一次修改都需要小心翼翼地梳理邏輯,極易牽一發(fā)而動全身,大大增加了開發(fā)和后期維護的成本。所以說,if-else語句大量嵌套時,會使代碼邏輯變得復(fù)雜,讓程序結(jié)構(gòu)混亂不堪,對代碼的整體質(zhì)量有著不容忽視的負面影響。 (二)引發(fā)效率問題除了對程序結(jié)構(gòu)有破壞作用之外,if-else語句在某些情況下還會引發(fā)效率問題。這就不得不提到現(xiàn)代CPU架構(gòu)中的相關(guān)知識了,像CPU的流水線結(jié)構(gòu)以及分支預(yù)測機制都和if-else語句的效率表現(xiàn)息息相關(guān)。 在現(xiàn)代 CPU執(zhí)行代碼時,常常采用流水線技術(shù),例如三級流水線,它在執(zhí)行一條指令時,會同時讀取后面的指令,并對其進行譯碼(也就是讀取、譯碼、執(zhí)行這幾個步驟同時進行),這種方式能大大提高執(zhí)行效率。但流水線技術(shù)并不是在所有時候都有效的,當程序中執(zhí)行到像if-else這類帶有跳轉(zhuǎn)結(jié)構(gòu)的語句時,情況就有所不同了。因為跳轉(zhuǎn)意味著后續(xù)部分代碼可能不會按順序執(zhí)行了,那提前讀取的那些指令也就沒了用處,所以CPU會丟棄流水線現(xiàn)有的結(jié)果,此時if語句相對于順序執(zhí)行的指令,就會產(chǎn)生幾個時鐘周期的差距。不過這并非if語句特有的問題,像switch、for等帶跳轉(zhuǎn)結(jié)構(gòu)的語句都會如此。 而分支預(yù)測則是為了進一步應(yīng)對跳轉(zhuǎn)語句對效率的影響而引入的技術(shù)。簡單來講,分支預(yù)測就是 CPU猜測條件判斷會走哪一路,如果猜對了,就能避免流水線停頓造成的時間浪費,可要是猜錯了,那么流水線中推測執(zhí)行的那些中間結(jié)果全部要放棄,得重新獲取正確的分支路線上的指令開始執(zhí)行,這就導(dǎo)致了程序執(zhí)行的延遲。并且,在大量使用if語句的地方,這種由于分支預(yù)測錯誤帶來的影響還會被放大,它有可能產(chǎn)生10 - 20個時鐘周期的影響。 例如,在處理排序數(shù)組和未排序數(shù)組時進行對比,有這樣一段代碼:
運行這段代碼會發(fā)現(xiàn),排序后的數(shù)組在執(zhí)行包含 if判斷的循環(huán)時,速度比未排序數(shù)組快很多,原因就是排序后的數(shù)據(jù)對于分支預(yù)測來說更有規(guī)律,分支預(yù)測器能更準確地猜測分支走向,而未排序的隨機數(shù)據(jù)則容易讓分支預(yù)測器猜錯,進而導(dǎo)致效率降低。雖然在部分場景下,if-else語句對效率的影響可以忽略不計,但它確實是存在效率方面的弊端的,也是我們在編程優(yōu)化時需要考慮的一個因素。 二、C#模式匹配閃亮登場![]() (一)類型檢查和轉(zhuǎn)換優(yōu)勢在 C#編程中,我們常常會遇到需要檢查對象是否為特定類型并且進行轉(zhuǎn)換的情況。以往,我們可能會使用傳統(tǒng)的as 和is 操作符來完成這類任務(wù)。例如,使用is 操作符判斷類型后,再通過強制類型轉(zhuǎn)換來獲取對應(yīng)類型的對象,像這樣:
或者使用as 操作符來嘗試轉(zhuǎn)換類型:
可以看到,使用傳統(tǒng)方式在進行類型轉(zhuǎn)換后,還需要額外進行null 檢查,以避免空引用異常的情況出現(xiàn),這樣就使得代碼變得相對繁瑣。 而模式匹配為我們提供了一種更為簡潔的方式來完成類型檢查和轉(zhuǎn)換任務(wù)。例如通過is 表達式結(jié)合聲明模式,我們可以在進行類型檢查的同時直接將結(jié)果賦值給變量,代碼如下:
在上述代碼中,當obj 的運行時類型是string 時,不僅完成了類型檢查,還自動將其賦值給了變量str,而且這個過程中隱含了對null 值的檢查。如果obj 為null,那么這個條件判斷就直接為false,不會進入后續(xù)的代碼塊,有效避免了空引用問題,使代碼更加精簡、安全且易讀。 (二)簡化復(fù)雜條件邏輯當業(yè)務(wù)邏輯變得復(fù)雜,涉及到多個條件和不同類型的判斷時,大量使用if-else 鏈或者傳統(tǒng)的switch 語句會讓代碼的可讀性變得很差。比如下面這樣一段模擬的傳統(tǒng)if-else 代碼:
隨著條件的增多以及類型的多樣化,這段代碼會越來越長,后續(xù)開發(fā)人員去理解其中的邏輯就會變得十分困難。 而使用模式匹配的switch 語句或者switch 表達式,就能很好地簡化這類復(fù)雜邏輯。例如:
通過模式匹配的switch,我們可以基于不同的類型以及對應(yīng)類型下的條件,清晰直觀地梳理出邏輯分支,把原本嵌套復(fù)雜的if-else 鏈轉(zhuǎn)換為簡潔明了的結(jié)構(gòu),讓代碼的邏輯一目了然,更易于理解和維護。 (三)解構(gòu)復(fù)合類型便捷性在處理復(fù)合類型(如元組、自定義類等)時,有時我們需要從中提取值來進行后續(xù)的操作。以往的做法可能需要編寫專門的解構(gòu)代碼,過程相對繁瑣。 例如對于一個包含姓名和年齡的Person 類:
如果不使用模式匹配,要提取其中的值可能是這樣的:
而借助模式匹配,我們可以直接在條件檢查中進行解構(gòu)。比如:
在上述代碼中,通過模式匹配的語法,在判斷person 對象是否符合條件的同時,直接將其內(nèi)部的Name 和Age 屬性解構(gòu)賦值到了對應(yīng)的變量n 和a 上,無需額外編寫復(fù)雜的解構(gòu)代碼,使得代碼更加簡潔,減少了不必要的代碼量,提升了代碼的整體可讀性。 (四)范圍檢查更輕松在很多編程場景中,我們需要對某個數(shù)值進行范圍檢查,判斷它是否落在特定的區(qū)間內(nèi)。在沒有模式匹配的情況下,我們可能會使用類似下面這樣的if 語句來實現(xiàn):
隨著范圍判斷條件的增多,代碼也會變得越來越復(fù)雜,可讀性逐漸變差。 不過,C# 9.0引入的關(guān)系模式讓范圍檢查的代碼得到了極大簡化。例如:
又或者像這樣:
通過關(guān)系模式的語法,我們可以直接在條件表達式中清晰地表達出范圍檢查的邏輯,使得代碼簡潔明了,一眼就能看出具體的范圍判斷情況,讓范圍檢查相關(guān)的代碼編寫和維護都變得更加輕松。 (五)邏輯組合更靈活在實際編程中,經(jīng)常會遇到需要對多個條件進行邏輯組合的情況,比如檢查一個值是否滿足多個條件之一或者是否滿足全部條件等。如果使用傳統(tǒng)的if-else 語句來實現(xiàn),往往會導(dǎo)致復(fù)雜的邏輯嵌套,代碼可讀性很差。 例如,判斷一個數(shù)字是否滿足特定的多個條件時,可能會寫成這樣:
可以看到,隨著條件增多和邏輯復(fù)雜度的提升,這樣的代碼理解起來就比較困難了。 而使用模式匹配中的邏輯模式,我們可以直接在模式匹配表達式中運用and、or 和not 等邏輯運算符來組合條件。代碼如下:
通過這種方式,邏輯組合變得更加清晰直觀,避免了復(fù)雜的邏輯嵌套,讓代碼結(jié)構(gòu)更簡潔,后續(xù)開發(fā)人員在閱讀和維護代碼時也能更容易理解其中的邏輯關(guān)系,提高了代碼的可維護性。 (六)數(shù)據(jù)驗證更緊湊在數(shù)據(jù)驗證場景中,驗證邏輯往往會涉及到多個方面,比如類型檢查、值范圍檢查以及特定屬性值檢查等。要是用傳統(tǒng)的方式來實現(xiàn),代碼可能會分散在多個不同的語句塊中,顯得比較松散且不易維護。 例如,驗證一個用戶輸入的數(shù)據(jù)是否符合要求,可能會有如下代碼:
而使用模式匹配,我們可以在單個表達式中完成所有這些檢查。比如:
通過模式匹配,將多種類型的驗證條件整合到了一起,使得驗證邏輯更加緊湊,代碼的結(jié)構(gòu)更加清晰,無論是修改驗證規(guī)則還是排查驗證相關(guān)的問題,都變得更加方便快捷,有效提升了代碼的可維護性。 (七)多態(tài)行為處理更簡單在處理需要依據(jù)對象類型執(zhí)行不同操作的多態(tài)行為時,傳統(tǒng)的做法通常是使用虛方法或者接口實現(xiàn)來完成。例如定義一個抽象基類Animal,然后不同的具體動物類(如Dog、Cat 等)繼承它并實現(xiàn)各自的行為方法:
當需要根據(jù)不同的動物對象執(zhí)行對應(yīng)的叫聲行為時,可能會這樣調(diào)用:
這種方式在類層次結(jié)構(gòu)比較復(fù)雜或者需要頻繁擴展修改行為時,就需要對類的繼承體系進行相應(yīng)調(diào)整,操作起來相對麻煩。 而模式匹配提供了一種更靈活的替代方式。比如:
甚至可以使用模式匹配的switch 表達式來簡化:
這樣在不修改原有類層次結(jié)構(gòu)的前提下,能夠更容易地擴展或修改不同類型對象對應(yīng)的行為,代碼的靈活性和可維護性都得到了提升。 (八)替代訪問者模式更簡潔在實現(xiàn)訪問者設(shè)計模式時,通常需要為每種類型單獨創(chuàng)建訪問者方法,當對象結(jié)構(gòu)比較復(fù)雜,涉及的類型眾多時,代碼量會變得很大,邏輯也會比較分散。 例如,假設(shè)有一個圖形的對象結(jié)構(gòu),包含圓形、矩形等不同類型圖形,使用傳統(tǒng)訪問者模式實現(xiàn)計算面積功能,可能會有如下代碼結(jié)構(gòu)(簡單示意):
使用時:
而通過模式匹配,可以作為一種更簡潔的替代方案。例如:
通過模式匹配,我們可以直接在一處處理所有類型情況,無需為每種類型單獨創(chuàng)建訪問者方法,大大簡化了代碼結(jié)構(gòu),讓代碼更加緊湊、易讀,在處理復(fù)雜對象結(jié)構(gòu)的相關(guān)邏輯時優(yōu)勢明顯。 三、實戰(zhàn)!用 C#模式匹配告別if-else(一)簡單邏輯場景應(yīng)用在實際編程中,有很多簡單的條件判斷邏輯場景,原本使用if-else 語句實現(xiàn)的代碼,都可以通過 C#模式匹配進行替換,讓代碼更加簡潔、易讀和易維護。 比如,我們有一個根據(jù)不同分數(shù)等級輸出對應(yīng)評價的場景,使用if-else 語句來寫可能是這樣的:
可以看到,雖然這段代碼邏輯比較清晰,但隨著條件的增多或者后續(xù)調(diào)整邏輯,代碼可能會變得越來越長且嵌套復(fù)雜。 現(xiàn)在我們使用 C#模式匹配的switch 表達式來改寫這段代碼,如下所示:
通過這樣的改寫,代碼一下子變得簡潔明了,各個分數(shù)區(qū)間的判斷條件清晰直觀地展示在switch 表達式中,一眼就能看出邏輯關(guān)系。而且如果后續(xù)需要增加新的分數(shù)等級判斷或者調(diào)整區(qū)間范圍,修改起來也很方便,只需要在switch 表達式中添加或修改對應(yīng)的分支即可,避免了if-else 語句層層嵌套帶來的代碼混亂問題,極大地提升了代碼的可維護性。 再比如,判斷一個數(shù)字是奇數(shù)還是偶數(shù)的場景,用傳統(tǒng)if-else 寫法是:
使用模式匹配可以改寫為:
同樣,改寫后的代碼更加簡潔,邏輯也更清晰,很容易理解和維護。所以在這種簡單邏輯場景下,C#模式匹配就已經(jīng)展現(xiàn)出了它相較于if-else 語句的優(yōu)勢,能幫助我們寫出更優(yōu)質(zhì)的代碼。 (二)復(fù)雜邏輯場景應(yīng)用接下來看一個相對復(fù)雜的業(yè)務(wù)邏輯案例,假設(shè)有一個電商系統(tǒng),根據(jù)不同的用戶角色(普通用戶、會員、管理員)以及不同的商品類型(電子產(chǎn)品、日用品、書籍)來計算折扣價格。 如果使用傳統(tǒng)的if-else 語句來實現(xiàn),代碼可能會像下面這樣:
可以想象,隨著用戶角色和商品類型的不斷增加,這段代碼會變得極其復(fù)雜,嵌套層級越來越深,可讀性極差,后續(xù)維護成本也會非常高。 現(xiàn)在我們使用 C#模式匹配的switch 表達式來重構(gòu)這段代碼,如下所示:
通過這樣的重構(gòu),原本繁雜的if-else 結(jié)構(gòu)被清晰的switch 表達式所替代,每個用戶角色和商品類型對應(yīng)的折扣計算邏輯一目了然。即使后續(xù)需要添加新的用戶角色或者商品類型以及對應(yīng)的折扣規(guī)則,也只需要在switch 表達式中添加相應(yīng)的分支即可,不會對現(xiàn)有的代碼結(jié)構(gòu)造成太大的影響,極大地提升了代碼的整體質(zhì)量和可維護性。 再舉一個涉及多種類型判斷以及復(fù)雜條件組合的例子,假設(shè)有一個圖形繪制系統(tǒng),根據(jù)傳入的圖形對象(圓形、矩形、三角形)以及一些額外的屬性(比如圓形的半徑范圍、矩形的長寬比例范圍、三角形的角度范圍等)來決定是否可以繪制該圖形。 用傳統(tǒng)if-else 語句可能寫成這樣(這里簡化示意部分邏輯判斷代碼):
當圖形種類增多以及每個圖形的判斷條件變得更復(fù)雜時,這段代碼會變得難以維護。 使用 C#模式匹配來重構(gòu),代碼如下:
通過模式匹配的switch 語句,我們可以基于不同的圖形類型以及對應(yīng)類型下的復(fù)雜條件,清晰地梳理出邏輯分支,把原本嵌套復(fù)雜的if-else 鏈轉(zhuǎn)換為簡潔明了的結(jié)構(gòu),讓代碼的邏輯更加清晰直觀,易于理解和維護,即使面對復(fù)雜的業(yè)務(wù)邏輯場景,也能輕松應(yīng)對,告別繁雜的if-else 語句帶來的困擾。 四、總結(jié)與展望(一)總結(jié)模式匹配優(yōu)勢通過前文的諸多示例與講解,我們可以清晰地看到 C#模式匹配在告別難以維護的if-else語句方面展現(xiàn)出了諸多優(yōu)勢。 首先,在類型檢查和轉(zhuǎn)換方面,模式匹配提供了更簡潔的方式,避免了傳統(tǒng)的as和is操作符使用后還需額外進行null檢查的繁瑣,讓代碼更加精簡、安全且易讀。 對于復(fù)雜條件邏輯,無論是涉及多個條件還是不同類型的判斷,模式匹配的switch語句或者表達式都能將原本嵌套復(fù)雜的if-else鏈轉(zhuǎn)換為簡潔明了的結(jié)構(gòu),極大提升了代碼的可讀性,使邏輯一目了然,便于后續(xù)開發(fā)人員理解與維護。 在解構(gòu)復(fù)合類型時,借助模式匹配可以直接在條件檢查中進行解構(gòu),無需編寫專門的解構(gòu)代碼,減少了不必要的代碼量,進一步增強了代碼整體的可讀性。 范圍檢查上,C# 9.0引入的關(guān)系模式讓相關(guān)代碼得到極大簡化,能直接在條件表達式中清晰表達范圍檢查邏輯,輕松應(yīng)對各種范圍判斷場景。 邏輯組合方面,利用模式匹配中的邏輯模式,可運用and、or和not等邏輯運算符在表達式中靈活組合條件,避免復(fù)雜的邏輯嵌套,使代碼結(jié)構(gòu)更簡潔,邏輯關(guān)系更易理解。 數(shù)據(jù)驗證場景中,模式匹配能夠把多種類型的驗證條件整合到單個表達式內(nèi),讓驗證邏輯更加緊湊,結(jié)構(gòu)更清晰,無論是修改驗證規(guī)則還是排查驗證問題都更加方便快捷。 處理多態(tài)行為時,模式匹配提供了更靈活的替代方式,無需對原有類層次結(jié)構(gòu)大動干戈就能輕松擴展或修改不同類型對象對應(yīng)的行為,提升了代碼的靈活性與可維護性。 而且在替代訪問者模式時,模式匹配可直接在一處處理所有類型情況,無需為每種類型單獨創(chuàng)建訪問者方法,大大簡化了代碼結(jié)構(gòu),在面對復(fù)雜對象結(jié)構(gòu)相關(guān)邏輯時優(yōu)勢顯著。 總之,C#模式匹配從多個維度提升了代碼的可讀性、可維護性,讓我們編寫的代碼更加優(yōu)質(zhì)、高效,告別以往if-else語句帶來的種種困擾。 (二)展望未來應(yīng)用發(fā)展隨著 C#語言的不斷發(fā)展,模式匹配的功能和應(yīng)用場景勢必會進一步擴展和深化。從過往的發(fā)展歷程來看,像C# 12中引入的let模式優(yōu)化了變量重用,高級遞歸模式為處理嵌套對象和復(fù)雜數(shù)據(jù)結(jié)構(gòu)提供了更多靈活性,這些新特性的出現(xiàn)不斷增強著模式匹配的能力。 在未來,或許我們能看到模式匹配在更多復(fù)雜業(yè)務(wù)場景中大放異彩,例如在處理大規(guī)模分布式系統(tǒng)中的數(shù)據(jù)交互與邏輯判斷時,模式匹配可以憑借其簡潔且強大的邏輯表達能力,更高效地梳理業(yè)務(wù)邏輯,減少代碼的復(fù)雜度。又或者在與新興技術(shù)如人工智能、大數(shù)據(jù)結(jié)合的應(yīng)用開發(fā)中,模式匹配能夠幫助開發(fā)人員更便捷地處理各種復(fù)雜的數(shù)據(jù)類型和條件判斷,加速開發(fā)進程。 同時,相信它在提升代碼性能方面也會有更多的優(yōu)化空間,在保證代碼可讀性和可維護性的同時,讓程序運行得更加高效。而且,隨著社區(qū)的不斷壯大以及開發(fā)人員對其探索的深入,會有更多創(chuàng)新性的使用方式被挖掘出來,模式匹配也將成為 C#編程中更加不可或缺的利器。 在此,鼓勵各位讀者積極在實際開發(fā)中運用這一技術(shù),不斷積累經(jīng)驗,緊跟 C#語言發(fā)展的步伐,利用模式匹配為我們帶來更優(yōu)質(zhì)、更易于維護的代碼,讓開發(fā)工作變得更加得心應(yīng)手。 該文章在 2024/12/24 10:30:21 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |