C#函數(shù)式編程中的惰性求值詳解
惰性求值
在開始介紹今天要講的知識(shí)之前,我們想要理解嚴(yán)格求值策略和非嚴(yán)格求值策略之間的區(qū)別,這樣我們才能夠深有體會(huì)的明白為什么需要利用這個(gè)技術(shù)。首先需要說明的是C#語(yǔ)言小部分采用了非嚴(yán)格求值策略,大部分還是嚴(yán)格求值策略。首先我們先演示非嚴(yán)格求值策略的情況,我們先在控制臺(tái)項(xiàng)目中寫一個(gè)DoOneThing方法。
然后在Main方法中寫入下面這串代碼:
然后我們運(yùn)行程序,會(huì)發(fā)現(xiàn)DoOneThing方法并沒有執(zhí)行。當(dāng)然這看起來也很正常,因?yàn)檫@是或,并且第一個(gè)已經(jīng)是true了。整個(gè)表達(dá)式就是true了,自然第二個(gè)就無需求值了。但是這恰恰就是非嚴(yán)格求值的策略,如果是嚴(yán)格求值策略的話整個(gè)表達(dá)式都會(huì)計(jì)算。接著就是嚴(yán)格求值策略的情況了,這個(gè)相信很多人都會(huì)立馬明白,首先我們需要再寫一個(gè)DoSomeThing方法:
接著修改Main方法:
執(zhí)行之后我們可以看到如下的結(jié)果:
但是我們可以清楚的看到a的值是false,根本不會(huì)使用b值,但是傳遞參數(shù)的時(shí)候已經(jīng)將DoOneThing方法執(zhí)行并賦值給b,假設(shè)這個(gè)方法是一個(gè)非常耗時(shí)的操作。那么我們就會(huì)白白浪費(fèi)掉這段時(shí)間,最后求得的值也沒有使用的到。而這正是嚴(yán)格求值策略,而今天的主要目標(biāo)就是改變這種情況,能夠在我們確定需要某個(gè)值的時(shí)候才計(jì)算。下面我們就可以開始改造這個(gè)方法,讓其能夠支持惰性求值。首先我們修改DoSomeThing方法:
這里我們將參數(shù)類型都改成了函數(shù),這樣將要傳遞進(jìn)來的參數(shù)都改變成函數(shù)。只有在我們需要的時(shí)候才執(zhí)行求值,否則是不會(huì)運(yùn)行的,對(duì)應(yīng)的Main方法中我們需要按照如下方式修改:
這里我們并不需要把DoOneThing方法的返回類型改掉,如果這樣的話。在現(xiàn)有項(xiàng)目上使用函數(shù)式編程就會(huì)顯得太麻煩了。這里我們僅僅只需要利用匿名函數(shù)就可以辦到了,下面我們可以看最后的執(zhí)行效果:
DoOneThing方法并沒有執(zhí)行,因?yàn)镈oSomeThing中根本沒有確定使用這個(gè)變量,這樣我們就能夠節(jié)省下這部分計(jì)算的時(shí)間,但是事實(shí)上我們還沒有結(jié)束,實(shí)際的開發(fā)中我們可能需要多次使用這個(gè)值,比如下面我們修改DoSomeThing方法:
并且在Main方法中調(diào)用DoSomeThing方法時(shí)將第一個(gè)參數(shù)改成true,然后執(zhí)行我們就可以看到下面的輸出結(jié)果:
DoOneThing方法被執(zhí)行了兩次,當(dāng)然我們可以利用局部變量保存,可能你會(huì)這么寫:
如果這么寫,那么我們的惰性求值就沒有任何意義了,因?yàn)橐贿M(jìn)入這個(gè)方法就執(zhí)行了這個(gè)方法,跟傳遞參數(shù)時(shí)直接將運(yùn)算后的結(jié)果賦值給b沒有任何區(qū)別了。當(dāng)然也有其他一些技巧可以避免,但是這些技巧可不是下面要講的內(nèi)容,我們可以將其封裝起來,比如我們可以寫個(gè)LazyS<T>類:
我們可以看到在構(gòu)造方法部分我們將對(duì)應(yīng)的函數(shù)作為參數(shù)接收并保存到function中,只有再調(diào)用Value時(shí)候會(huì)執(zhí)行該函數(shù)并將值保存,并且在下次調(diào)用時(shí),如果已經(jīng)求值過則直接返回緩存過的值,這樣就能夠避免重復(fù)的執(zhí)行了,對(duì)應(yīng)的我們還要修改DoSomeThing方法和Main方法:
最終執(zhí)行后我們可以看到僅執(zhí)行了一次DoOneThing方法:
一些讀者可能為問為什么類名不要Lazy而是加個(gè)S,因?yàn)?net中已經(jīng)為我們包含了Lazy<T>類,相信很多人基本上從沒有用過。只知道Func和Action的存在,下面我們修改我們的代碼直接利用自帶的:
最終的結(jié)果之前的是一摸一樣,當(dāng)然系統(tǒng)自帶的Lazy功能更多,并且支持多線程。
就到這里為止吧,周五了大家已經(jīng)按耐不住了,寫了太多可能就沒有心思往下看了,所以將這些全部一個(gè)一個(gè)拆分開來細(xì)講。
- C# ODP.NET 調(diào)用Oracle函數(shù)返回值時(shí)報(bào)錯(cuò)的一個(gè)解決方案
- C#中字段、屬性、只讀、構(gòu)造函數(shù)賦值、反射賦值的問題
- C# 中如何取絕對(duì)值函數(shù)
- asp.net(c#)獲取內(nèi)容第一張圖片地址的函數(shù)
- C#關(guān)于Task.Yeild()函數(shù)的討論
- C# 構(gòu)造函數(shù)如何調(diào)用虛方法
- 淺談C# 構(gòu)造方法(函數(shù))
- C#后臺(tái)調(diào)用前臺(tái)JS函數(shù)方法
- C#使用ILGenerator動(dòng)態(tài)生成函數(shù)的簡(jiǎn)單代碼
- C#中加載dll并調(diào)用其函數(shù)的實(shí)現(xiàn)方法
- 淺析C# 函數(shù)的傳值與傳址
相關(guān)文章
基于C# 寫一個(gè) Redis 數(shù)據(jù)同步小工具
Redis支持主從同步。數(shù)據(jù)可以從主服務(wù)器向任意數(shù)量的從服務(wù)器上同步,從服務(wù)器可以是關(guān)聯(lián)其他從服務(wù)器的主服務(wù)器。這篇文章主要介紹了用 C# 寫一個(gè) Redis 數(shù)據(jù)同步小工具,需要的朋友可以參考下2020-02-02C#解析json字符串總是多出雙引號(hào)的原因分析及解決辦法
json好久沒用了,今天在用到j(luò)son的時(shí)候,發(fā)現(xiàn)對(duì)字符串做解析的時(shí)候總是多出雙引號(hào),下面給大家介紹C#解析json字符串總是多出雙引號(hào)的原因分析及解決辦法,需要的朋友參考下吧2016-03-03基于Avalonia實(shí)現(xiàn)自定義彈窗的示例詳解
對(duì)于使用avalonia的時(shí)候某些功能需要到一些提示,比如異常或者成功都需要對(duì)用戶進(jìn)行提示,所以需要單獨(dú)實(shí)現(xiàn)彈窗功能,并且可以自定義內(nèi)部組件,這一期將手動(dòng)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的小彈窗,并且很容易自定義,希望大家喜歡2023-02-02Python設(shè)計(jì)模式編程中的備忘錄模式與對(duì)象池模式示例
這篇文章主要介紹了Python設(shè)計(jì)模式編程中的備忘錄模式與對(duì)象池模式,文中分別舉了表單和線程的相關(guān)示例,需要的朋友可以參考下2016-02-02C#實(shí)現(xiàn)的調(diào)用DOS命令操作類實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的調(diào)用DOS命令操作類,實(shí)例分析了C#調(diào)用系統(tǒng)常用DOS命令的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04C# 中使用NModbus4通信庫(kù)執(zhí)行寫操作
在C#中NModbus4庫(kù)提供了一個(gè)方便的方式來與支持Modbus協(xié)議的設(shè)備進(jìn)行交互,本文就來介紹了使用NModbus4通信庫(kù)執(zhí)行寫操作,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03