C#中的產生介紹 - 它是什麼,如何使用,以及什麼時候有用
當您第一次接觸到C#中的yield關鍵字時,可能會感到困惑。 它到底是如何工作的? 什麼時候應該使用yield return而不是傳統的return語句? 為了全面了解,我們將依據Tim Corey優秀的YouTube教學進行詳細解釋:"Intro to Yield in C# - What it is, how to use it, and when it is useful"。
在本指南中,我們將通過時間戳標記引用Tim的影片中的具體點以便於導航,並包含實際範例來展示yield如何改變資料流、大型集合和延遲評估的處理方式。
介紹C#中的Yield關鍵字
Tim首先介紹yield關鍵字,並強調它對於第一次接觸的開發者來說通常令人困惑。他解釋說,yield語句允許方法暫停執行,保持其狀態,然後在下一次調用時從中斷的位置繼續。 Tim強調理解yield對於有效處理資料尤為重要,特別是處理大資料集或自定義迭代邏輯時。
設置簡單範例:Class Program和Static Void Main
為了避免分心,Tim在Visual Studio中建立了一個簡單的Console Appliation,稱為"YieldDemoApp"。

Yield在C#中的實際作用
Tim接著更深入地探討理論。 在2:04,他描述了yield行為:不再一次性處理整個集合,yield語句位於其位置,即像將拇指放入一本書中一樣,允許執行暫停並稍後恢復。
這種行為對於延遲執行至關重要,因為值僅在需要時生成,而不是事先全部計算。 Tim的描述清晰地奠定了理解yield return的基礎。
撰寫演示程式碼
在Class Program的static void Main方法中,他設置了基本的開模型和結束消息,如"Start of the app"和"End of the app",使用Console.WriteLine來幫助明確顯示流程,特別是當使用foreach迴圈時。
這個初始程式碼範例純粹關注於yield的實現,不涉及任何UI的複雜性。
建立PersonModel類
為了演示,Tim建立一個具有FirstName和LastName屬性和構造函式的PersonModel類。 當PersonModel物件被建立時,會列印一條消息,指示初始化了哪個使用者。 這有助於形象化物件何時被建立和何時被消耗。

這個簡單的生成程式碼步驟為使用自定義迭代器打下基礎。
構建DataAccess類並使用傳統的List返回
在5:06,Tim轉到DataAccess類,並用一個返回IEnumerable

這個迭代器方法在開始迭代之前立即將所有物件載入到記憶體中——這是Tim後來與使用yield作對比的一個重要點。

展示List的記憶體用量
運行foreach迴圈後,Tim顯示所有三個使用者都在讀取第一個元素之前建立。 這突出顯示了一個潛在問題,當處理大型集合或大資料集時——高記憶體用量。

Tim解釋說,如果我們有一千個使用者,即使我們只需要幾個,用一千個物件也會建立,導致記憶體分配效率低下。
變更到Yield Return以進行延遲執行
在10:01,Tim修改GetPeople使用yield return,而不是建立一個臨時集合 (如List)。 每個yield return語句直接生成一個PersonModel。
這關鍵程式碼在方法內允許延遲評估,foreach需要下一個元素時才生成。
Tim還澄清方法的返回型別必須是IEnumerable
除錯:編譯器生成Yield程式碼
Tim使用斷點逐步演示過程。 他顯示在第一次MoveNext調用之前,序列是空的。 只有當foreach需要下一個值時,編譯器會觸發迭代器塊並執行yield return num行,這會初始化並返回PersonModel。

Tim強調編譯器在底層生成專用的狀態機來管理暫停和恢復的執行。
使用Yield Return的好處和效率
Tim解釋為什麼yield如此高效:
您可以一次獲取一個記錄。
您可以限制需要的int數量。
您避免將整個集合載入到記憶體中。
- 您提高了可擴展性,特別是在處理大型文件或資料流時。
通過使用LINQ的.Take(2),Tim演示即使存在三個yield return語句,也只有兩個物件被初始化——強調延遲執行的作用。
實例:使用Yield的質數生成器
Tim在Generators類內構建一個新的靜態IEnumerable
這個範例顯示yield對於安全地處理無限序列至關重要。
沒有yield,程式碼會因為無限的記憶體消耗而崩潰。 然而,使用yield,延遲執行確保根據需求生數。
使用Take()獲取質數
Tim然後演示如何安全地只提取固定數量的質數:
var primeNumbers = Generators.GetPrimeNumbers().Take(10000);var primeNumbers = Generators.GetPrimeNumbers().Take(10000);這段程式碼寫在static void Main中,能有效地只提取10,000個質數。
因為yield return逐個生成數字,記憶體使用量保持低。
自定義迭代:使用GetEnumerator和MoveNext
Tim進一步解釋如何手動控制迭代。
他建立一個var iterator = primeNumbers.GetEnumerator(),然後用int i的for迴圈並調用iterator.MoveNext()來手動獲取元素。
這種手動方法實現了自定義迭代——只有在需要時才請求下一個值,並顯示該方法從上次暫停的地方準確恢復。
常見錯誤:在Yield的集合上使用ToList()
在36:45,Tim警告:將yield序列轉換為List並用.ToList()會導致立即全面評估。
如果您在無限序列上調用.ToList(),您風險崩潰您的應用程式。
Tim強調yield return用於延遲評估,而調用.ToList()打破了這一模式,強制記憶體全面實現。
當使用LINQ方法時,Tim建議謹慎考慮在何處引入.ToList()。
總結:為什麼Yield是強大的工具
Tim在結束時強調,儘管yield關鍵字增加了輕微的負擔(持有狀態機),但因減少記憶體使用和延遲評估的好處,yield在處理以下方面是一個強大的工具:
大資料集
大文件
自定義迭代器
無限序列
資料流
- 延遲處理
他建議在不同專案中練習使用yield,以更深入地理解yield return並避免常見的陷阱。
Tim最後鼓勵觀眾分享他們在生產程式碼中如何使用yield。
結論
通過學習Tim Corey的影片,我們看到了yield關鍵字對C#帶來的巨大好處。 從建立自定義迭代器到有效管理大型集合,yield return使得函式返回更智能和更為記憶體高效。 無論您正在處理var number, var point, var reader, var connection, 或是大型資料集,掌握yield可以顯著提升您的C#編碼技能。
如果您以前沒有探索過使用yield,現在是通過簡單例子進行練習並更好地理解yield return如何在C#編譯器內部運作的絕佳時機。 一定要查看Tim的官方YouTube頻道以獲得更多見解豐富的影片。

