C#函數(shù)式編程中的惰性求值詳解
惰性求值
在開始介紹今天要講的知識之前,我們想要理解嚴(yán)格求值策略和非嚴(yán)格求值策略之間的區(qū)別,這樣我們才能夠深有體會的明白為什么需要利用這個技術(shù)。首先需要說明的是C#語言小部分采用了非嚴(yán)格求值策略,大部分還是嚴(yán)格求值策略。首先我們先演示非嚴(yán)格求值策略的情況,我們先在控制臺項目中寫一個DoOneThing方法。

然后在Main方法中寫入下面這串代碼:

然后我們運行程序,會發(fā)現(xiàn)DoOneThing方法并沒有執(zhí)行。當(dāng)然這看起來也很正常,因為這是或,并且第一個已經(jīng)是true了。整個表達式就是true了,自然第二個就無需求值了。但是這恰恰就是非嚴(yán)格求值的策略,如果是嚴(yán)格求值策略的話整個表達式都會計算。接著就是嚴(yán)格求值策略的情況了,這個相信很多人都會立馬明白,首先我們需要再寫一個DoSomeThing方法:

接著修改Main方法:

執(zhí)行之后我們可以看到如下的結(jié)果:

但是我們可以清楚的看到a的值是false,根本不會使用b值,但是傳遞參數(shù)的時候已經(jīng)將DoOneThing方法執(zhí)行并賦值給b,假設(shè)這個方法是一個非常耗時的操作。那么我們就會白白浪費掉這段時間,最后求得的值也沒有使用的到。而這正是嚴(yán)格求值策略,而今天的主要目標(biāo)就是改變這種情況,能夠在我們確定需要某個值的時候才計算。下面我們就可以開始改造這個方法,讓其能夠支持惰性求值。首先我們修改DoSomeThing方法:

這里我們將參數(shù)類型都改成了函數(shù),這樣將要傳遞進來的參數(shù)都改變成函數(shù)。只有在我們需要的時候才執(zhí)行求值,否則是不會運行的,對應(yīng)的Main方法中我們需要按照如下方式修改:

這里我們并不需要把DoOneThing方法的返回類型改掉,如果這樣的話。在現(xiàn)有項目上使用函數(shù)式編程就會顯得太麻煩了。這里我們僅僅只需要利用匿名函數(shù)就可以辦到了,下面我們可以看最后的執(zhí)行效果:

DoOneThing方法并沒有執(zhí)行,因為DoSomeThing中根本沒有確定使用這個變量,這樣我們就能夠節(jié)省下這部分計算的時間,但是事實上我們還沒有結(jié)束,實際的開發(fā)中我們可能需要多次使用這個值,比如下面我們修改DoSomeThing方法:

并且在Main方法中調(diào)用DoSomeThing方法時將第一個參數(shù)改成true,然后執(zhí)行我們就可以看到下面的輸出結(jié)果:

DoOneThing方法被執(zhí)行了兩次,當(dāng)然我們可以利用局部變量保存,可能你會這么寫:

如果這么寫,那么我們的惰性求值就沒有任何意義了,因為一進入這個方法就執(zhí)行了這個方法,跟傳遞參數(shù)時直接將運算后的結(jié)果賦值給b沒有任何區(qū)別了。當(dāng)然也有其他一些技巧可以避免,但是這些技巧可不是下面要講的內(nèi)容,我們可以將其封裝起來,比如我們可以寫個LazyS<T>類:

我們可以看到在構(gòu)造方法部分我們將對應(yīng)的函數(shù)作為參數(shù)接收并保存到function中,只有再調(diào)用Value時候會執(zhí)行該函數(shù)并將值保存,并且在下次調(diào)用時,如果已經(jīng)求值過則直接返回緩存過的值,這樣就能夠避免重復(fù)的執(zhí)行了,對應(yīng)的我們還要修改DoSomeThing方法和Main方法:


最終執(zhí)行后我們可以看到僅執(zhí)行了一次DoOneThing方法:

一些讀者可能為問為什么類名不要Lazy而是加個S,因為.net中已經(jīng)為我們包含了Lazy<T>類,相信很多人基本上從沒有用過。只知道Func和Action的存在,下面我們修改我們的代碼直接利用自帶的:

最終的結(jié)果之前的是一摸一樣,當(dāng)然系統(tǒng)自帶的Lazy功能更多,并且支持多線程。
就到這里為止吧,周五了大家已經(jīng)按耐不住了,寫了太多可能就沒有心思往下看了,所以將這些全部一個一個拆分開來細(xì)講。
- C# ODP.NET 調(diào)用Oracle函數(shù)返回值時報錯的一個解決方案
- C#中字段、屬性、只讀、構(gòu)造函數(shù)賦值、反射賦值的問題
- C# 中如何取絕對值函數(shù)
- asp.net(c#)獲取內(nèi)容第一張圖片地址的函數(shù)
- C#關(guān)于Task.Yeild()函數(shù)的討論
- C# 構(gòu)造函數(shù)如何調(diào)用虛方法
- 淺談C# 構(gòu)造方法(函數(shù))
- C#后臺調(diào)用前臺JS函數(shù)方法
- C#使用ILGenerator動態(tài)生成函數(shù)的簡單代碼
- C#中加載dll并調(diào)用其函數(shù)的實現(xiàn)方法
- 淺析C# 函數(shù)的傳值與傳址
相關(guān)文章
Unity shader實現(xiàn)移動端模擬深度水效果
這篇文章主要為大家詳細(xì)介紹了Unity shader實現(xiàn)移動端模擬深度水效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-05-05
C#在Entity Framework中實現(xiàn)事務(wù)回滾
這篇文章介紹了C#在Entity Framework中實現(xiàn)事務(wù)回滾的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08
C#實現(xiàn)數(shù)據(jù)包加密與解密實例詳解
這篇文章主要介紹了C#實現(xiàn)數(shù)據(jù)包加密與解密的方法,是一項很實用的技能,需要的朋友可以參考下2014-07-07

