跳至頁尾內容
Iron Academy Logo
學習C#
學習C#

其他類別

C#中的產生介紹 - 它是什麼,如何使用,以及什麼時候有用

Tim Corey
43m 58s

當您第一次接觸到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"。

Understanding Yield In Csharp 1 related to 設置簡單範例:Class Program和Static Void Main

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物件被建立時,會列印一條消息,指示初始化了哪個使用者。 這有助於形象化物件何時被建立和何時被消耗。

Understanding Yield In Csharp 2 related to 建立PersonModel類

這個簡單的生成程式碼步驟為使用自定義迭代器打下基礎。

構建DataAccess類並使用傳統的List返回

在5:06,Tim轉到DataAccess類,並用一個返回IEnumerable的GetPeople方法。 最初,返回值是一個包含三個PersonModel實例的List:Tim Corey, Sue Storm, 和 Jane Smith。

Understanding Yield In Csharp 3 related to 構建DataAccess類並使用傳統的List返回

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

Understanding Yield In Csharp 4 related to 構建DataAccess類並使用傳統的List返回

展示List的記憶體用量

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

Understanding Yield In Csharp 5 related to 展示List的記憶體用量

Tim解釋說,如果我們有一千個使用者,即使我們只需要幾個,用一千個物件也會建立,導致記憶體分配效率低下。

變更到Yield Return以進行延遲執行

在10:01,Tim修改GetPeople使用yield return,而不是建立一個臨時集合 (如List)。 每個yield return語句直接生成一個PersonModel。

這關鍵程式碼在方法內允許延遲評估,foreach需要下一個元素時才生成。

Tim還澄清方法的返回型別必須是IEnumerable,使用List會破壞延遲執行的目的。

除錯:編譯器生成Yield程式碼

Tim使用斷點逐步演示過程。 他顯示在第一次MoveNext調用之前,序列是空的。 只有當foreach需要下一個值時,編譯器會觸發迭代器塊並執行yield return num行,這會初始化並返回PersonModel。

Understanding Yield In Csharp 6 related to 除錯:編譯器生成Yield程式碼

Tim強調編譯器在底層生成專用的狀態機來管理暫停和恢復的執行。

使用Yield Return的好處和效率

Tim解釋為什麼yield如此高效:

  • 您可以一次獲取一個記錄。

  • 您可以限制需要的int數量。

  • 您避免將整個集合載入到記憶體中。

  • 您提高了可擴展性,特別是在處理大型文件或資料流時。

通過使用LINQ的.Take(2),Tim演示即使存在三個yield return語句,也只有兩個物件被初始化——強調延遲執行的作用。

實例:使用Yield的質數生成器

Tim在Generators類內構建一個新的靜態IEnumerableGetPrimeNumbers()方法。 在這個無限迴圈中,Tim使用helper IsPrimeNumber(int number)函式來檢查其是否為質數。 如果數字是質數,他使用yield return number來發送它。

這個範例顯示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頻道以獲得更多見解豐富的影片。

Hero Worlddot related to C#中的產生介紹 - 它是什麼,如何使用,以及什麼時候有用
Hero Affiliate related to C#中的產生介紹 - 它是什麼,如何使用,以及什麼時候有用

分享您所愛以賺取更多報酬

您是否為使用 .NET、C#、Java、Python 或 Node.js 的開發者建立內容?將您的專業知識轉化為額外收入!

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話