關於yield關鍵字,網上有很多文章介紹了,但是看了之後,雖然明白了"哦,原來是這麼回事",但是在日常開發中並沒有真正的用起來,所以,寫此一篇,介紹一下在真正的項目中怎麼使用這個關鍵字。 開始我的正文介紹之前,可以先看一下微軟的官方文檔是怎麼介紹yield關鍵字的,傳送門:https://docs. ...
關於yield關鍵字,網上有很多文章介紹了,但是看了之後,雖然明白了"哦,原來是這麼回事",但是在日常開發中並沒有真正的用起來,所以,寫此一篇,介紹一下在真正的項目中怎麼使用這個關鍵字。
開始我的正文介紹之前,可以先看一下微軟的官方文檔是怎麼介紹yield關鍵字的,傳送門:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/yield
在這裡我新建了一個控制台程式,用於輸出斐波那契數列,代碼如下:我們直接在Main方法中輸出斐波那契數列,這個也沒有什麼問題,很完美,但是考慮到實際開發中不可能把所有的處理都寫在程式入口,所以我們考慮對這段代碼封裝一個方法V1
static void Main(string[] args) {int a = 0, b = 1, c = 0; for (int i = 0; i < 10; i++) { Console.WriteLine("{0}", b); c = a + b; a = b; b = c; } //V1(10); //foreach (var i in V2(10)) //{ // Console.WriteLine(i); //} //foreach (var i in V3(10)) //{ // Console.WriteLine(i); //} Console.ReadKey(); }
方法V1代碼如下:與Main方法中的代碼段是一模一樣的,那麼有經驗的同學肯定會想,既然已經封裝了方法,那麼方法的輸出應該封裝成返回值,返回給Main方法,然後再輸出到控制台,於是我們再次修改,封裝成方法V2
private static void V1(int number) { Console.WriteLine("V1"); int a = 0, b = 1, c = 0; for (int i = 0; i < number; i++) { Console.WriteLine("{0}", b); c = a + b; a = b; b = c; } }
方法V2代碼如下:方法V2中創建了一個List<int>的列表,用來接收方法返回的結果,然後在Main方法中輸出。那麼這裡有什麼問題呢?問題就是如果迴圈的基數很大,那麼,我們的List中的item就很大,占用記憶體也會隨之增加,於是,我們在此基礎上再次改造成方法V3
private static IEnumerable<int> V2(int number) { Console.WriteLine("V2"); List<int> vs = new List<int>(); int a = 0, b = 1, c = 0; for (int i = 0; i < number; i++) { vs.Add(b); c = a + b; a = b; b = c; } return vs; }
方法V3代碼如下:這裡便用到了關鍵字yield,正如官方文檔中所述,迭代器方法運行到 yield return
語句時,會返回一個 expression
,並保留當前在代碼中的位置。 下次調用迭代器函數時,將從該位置重新開始執行。這樣的話,記憶體不會隨著基數的增加而增加,而效果卻是一模一樣的。
private static IEnumerable<int> V3(int number) { Console.WriteLine("V3"); int a = 0, b = 1, c = 0; for (int i = 0; i < number; i++) { yield return b; c = a + b; a = b; b = c; } }
那麼,總結經驗,在你需要返回一個繼承自IEnumerable的集合類型的時候,就可以使用這個yield關鍵字了。
最後的運行效果: