C#函數(shù)式編程中的惰性求值詳解
惰性求值
在開始介紹今天要講的知識之前,我們想要理解嚴格求值策略和非嚴格求值策略之間的區(qū)別,這樣我們才能夠深有體會的明白為什么需要利用這個技術。首先需要說明的是C#語言小部分采用了非嚴格求值策略,大部分還是嚴格求值策略。首先我們先演示非嚴格求值策略的情況,我們先在控制臺項目中寫一個DoOneThing方法。
然后在Main方法中寫入下面這串代碼:
然后我們運行程序,會發(fā)現(xiàn)DoOneThing方法并沒有執(zhí)行。當然這看起來也很正常,因為這是或,并且第一個已經(jīng)是true了。整個表達式就是true了,自然第二個就無需求值了。但是這恰恰就是非嚴格求值的策略,如果是嚴格求值策略的話整個表達式都會計算。接著就是嚴格求值策略的情況了,這個相信很多人都會立馬明白,首先我們需要再寫一個DoSomeThing方法:
接著修改Main方法:
執(zhí)行之后我們可以看到如下的結(jié)果:
但是我們可以清楚的看到a的值是false,根本不會使用b值,但是傳遞參數(shù)的時候已經(jīng)將DoOneThing方法執(zhí)行并賦值給b,假設這個方法是一個非常耗時的操作。那么我們就會白白浪費掉這段時間,最后求得的值也沒有使用的到。而這正是嚴格求值策略,而今天的主要目標就是改變這種情況,能夠在我們確定需要某個值的時候才計算。下面我們就可以開始改造這個方法,讓其能夠支持惰性求值。首先我們修改DoSomeThing方法:
這里我們將參數(shù)類型都改成了函數(shù),這樣將要傳遞進來的參數(shù)都改變成函數(shù)。只有在我們需要的時候才執(zhí)行求值,否則是不會運行的,對應的Main方法中我們需要按照如下方式修改:
這里我們并不需要把DoOneThing方法的返回類型改掉,如果這樣的話。在現(xiàn)有項目上使用函數(shù)式編程就會顯得太麻煩了。這里我們僅僅只需要利用匿名函數(shù)就可以辦到了,下面我們可以看最后的執(zhí)行效果:
DoOneThing方法并沒有執(zhí)行,因為DoSomeThing中根本沒有確定使用這個變量,這樣我們就能夠節(jié)省下這部分計算的時間,但是事實上我們還沒有結(jié)束,實際的開發(fā)中我們可能需要多次使用這個值,比如下面我們修改DoSomeThing方法:
并且在Main方法中調(diào)用DoSomeThing方法時將第一個參數(shù)改成true,然后執(zhí)行我們就可以看到下面的輸出結(jié)果:
DoOneThing方法被執(zhí)行了兩次,當然我們可以利用局部變量保存,可能你會這么寫:
如果這么寫,那么我們的惰性求值就沒有任何意義了,因為一進入這個方法就執(zhí)行了這個方法,跟傳遞參數(shù)時直接將運算后的結(jié)果賦值給b沒有任何區(qū)別了。當然也有其他一些技巧可以避免,但是這些技巧可不是下面要講的內(nèi)容,我們可以將其封裝起來,比如我們可以寫個LazyS<T>類:
我們可以看到在構(gòu)造方法部分我們將對應的函數(shù)作為參數(shù)接收并保存到function中,只有再調(diào)用Value時候會執(zhí)行該函數(shù)并將值保存,并且在下次調(diào)用時,如果已經(jīng)求值過則直接返回緩存過的值,這樣就能夠避免重復的執(zhí)行了,對應的我們還要修改DoSomeThing方法和Main方法:
最終執(zhí)行后我們可以看到僅執(zhí)行了一次DoOneThing方法:
一些讀者可能為問為什么類名不要Lazy而是加個S,因為.net中已經(jīng)為我們包含了Lazy<T>類,相信很多人基本上從沒有用過。只知道Func和Action的存在,下面我們修改我們的代碼直接利用自帶的:
最終的結(jié)果之前的是一摸一樣,當然系統(tǒng)自帶的Lazy功能更多,并且支持多線程。
就到這里為止吧,周五了大家已經(jīng)按耐不住了,寫了太多可能就沒有心思往下看了,所以將這些全部一個一個拆分開來細講。
- C# ODP.NET 調(diào)用Oracle函數(shù)返回值時報錯的一個解決方案
- C#中字段、屬性、只讀、構(gòu)造函數(shù)賦值、反射賦值的問題
- C# 中如何取絕對值函數(shù)
- asp.net(c#)獲取內(nèi)容第一張圖片地址的函數(shù)
- C#關于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ù)的傳值與傳址
相關文章
基于C# 寫一個 Redis 數(shù)據(jù)同步小工具
Redis支持主從同步。數(shù)據(jù)可以從主服務器向任意數(shù)量的從服務器上同步,從服務器可以是關聯(lián)其他從服務器的主服務器。這篇文章主要介紹了用 C# 寫一個 Redis 數(shù)據(jù)同步小工具,需要的朋友可以參考下2020-02-02