在之前幾篇有介紹過一些C#的修飾詞,這次要介紹的是yield修飾詞,你一定覺得C#怎麼這麼多修飾詞。是的,C#的修飾詞就是這麼多,但這次要介紹的yield蠻有趣的,在C++或java可是找不到這種功能的修飾詞。
yield return的用法舉個例子來說,當我在迴圈中遍歷(iterate)每個元素,如果遇到符合條件的元素時,一般的做法通常是new一個集合的instance,再逐一將符合的元素加入集合中,最後再回傳整個整理後的集合;yield return的做法為當遇到符合條件的元素時,即刻將該元素回傳回上一層進行後續運算,後續運算完後再回到迴圈中找尋下一個元素。在MSDN上對於yield的使用上還有提到一些限制:
下面是用圖解(下面程式碼流程)來表示yield return與一般做法的差異:
yield:
一開始list只單純指向GetEvenNumByYield方法而不實際執行,當foreach開始使用到list時,才執行GetEvenNumByYield方法,執行過程中只要遇到符合的元素就直接回傳回去進行sum的加總運算,sum運算後再回到GetEvenNumByYield方法進行下一個iteration。
一般做法(Temp):
一開始list會呼叫GetEvenNumByTemp方法運算後取得集合,GetEvenNumByTemp方法內部運算時會將符合的元素暫存在一個temp的list中,整個運算完後將temp list回傳給主程式,接著主程式在利用這個處理完的list一一取出元素進行sum加總運算。
以下為範例程式碼,顯示 yield return 與一般Temp List的差異:
參考來源:
MSDN - yield (C# 參考)
yield return的用法舉個例子來說,當我在迴圈中遍歷(iterate)每個元素,如果遇到符合條件的元素時,一般的做法通常是new一個集合的instance,再逐一將符合的元素加入集合中,最後再回傳整個整理後的集合;yield return的做法為當遇到符合條件的元素時,即刻將該元素回傳回上一層進行後續運算,後續運算完後再回到迴圈中找尋下一個元素。在MSDN上對於yield的使用上還有提到一些限制:
- 回傳類型必須為IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T>
- 不可包含任何 ref 與 out 參數
- 匿名方法與unsafe區塊不可使用yield
下面是用圖解(下面程式碼流程)來表示yield return與一般做法的差異:
yield:
一般做法(Temp):
一開始list會呼叫GetEvenNumByTemp方法運算後取得集合,GetEvenNumByTemp方法內部運算時會將符合的元素暫存在一個temp的list中,整個運算完後將temp list回傳給主程式,接著主程式在利用這個處理完的list一一取出元素進行sum加總運算。
以下為範例程式碼,顯示 yield return 與一般Temp List的差異:
static void Main(string[] args) { var myList = new List<int>(); for(var i = 0; i < 10000000; i++) { myList.Add(i); } var timeList = new List<long>(); for(var i = 0; i < 10; i++) { var sum = 0; var sw = new Stopwatch(); sw.Start(); var list = getEvenNumByYield(myList); //var list = getEvenNumByLinq(myList); //var list = getEvenNumByTemp(myList); foreach(var l in list) { sum += l; } // Reuse collection foreach(var l in list) { sum -= l; } sw.Stop(); timeList.Add(sw.ElapsedMilliseconds); Console.WriteLine("Exe time: {0} ms", sw.ElapsedMilliseconds); } Console.WriteLine("Average: {0} ms", (double) timeList.Sum() / 10); Console.WriteLine("Memory Usage: {0}", Process.GetCurrentProcess().PrivateMemorySize64); } static IEnumerable<int> getEvenNumByYield(IEnumerable<int> collection) { foreach(var i in collection) { if(i % 2 == 0) yield return i; } } static IEnumerable<int> getEvenNumByLinq(IEnumerable<int> collection) { return collection.ToList().Where(i => i % 2 == 0); } static IEnumerable<int> getEvenNumByTemp(IEnumerable<int> collection) { var temp = new List<int>(); foreach(var i in collection) { if(i % 2 == 0) temp.Add(i); } return temp; }
參考來源:
MSDN - yield (C# 參考)
Thanks you very much.
回覆刪除標題的 yield 錯誤哦~
回覆刪除