1. 程式人生 > 實用技巧 >迭代器 與 foreach 的區別

迭代器 與 foreach 的區別

迭代器的常見運用--Eg:有一組資料 需要對每個符合條件的陣列 進行記錄

       static void Main()
        {
            int[] s = new int[] { 1, 2, 8 };
            foreach (int term in GetSingleDigitNumbers(s))
            {
                Console.WriteLine(term);
            }

            Console.ReadKey();
        }
       
        public static IEnumerable<int> GetSingleDigitNumbers(int[] s)
        {
            foreach (var item in s)
            {
                if (item%2==0)
                {
                    yield return item;
                }              
            }
        }

結果:

這裡看來 好像直接foreach就能實現
起先我並不明白 兩者使用起來到底有什麼區別 直到我看到以下例項

IEnumerable<int> Fibonacci(int count)
{
  int prev = 1;
  int curr = 1;
  for (int i = 0; i < count; i++)
  {
    yield return prev; //把程式控制權交回呼叫者 同時保留方法本地狀態,等到呼叫者拿到返回的值後 該方法繼續往後執行
    int temp = prev + curr;
    prev = curr;
    curr = temp;
  }
}

void Main()
{
  foreach (int term in Fibonacci(10))
  {
    Console.WriteLine(term);
  }
}

對應輸出結果

可發現呼叫Fibonacci 每次返回結果後 依舊繼續往後執行 直至此次for結束後 繼續進行Fibonacci的for迴圈 直至迴圈結束 這樣就將符合條件的一組值返回給了呼叫者

而foreach迴圈 return後 後續是不會執行的 且 foreach依賴於 .NET Core 庫中定義的 2 個泛型介面,才能生成迴圈訪問集合所需的程式碼:IEnumerable 和 IEnumerator

此外iterators是使用時 才真正呼叫執行的 Eg:

  static void Main()
        {
            int[] s = new int[] { 1, 2, 8 };
            var p = GetSingleDigitNumbers(s);//此時直接返回符合條件的 IEnumerable<int>{2,8};不會真正的執行方法內操作【 Console.WriteLine("The method was called.");】

            //如果p不被呼叫 則永遠不會執行GetSingleDigitNumbers方法內額外的操作【 Console.WriteLine("The method was called.");】
            foreach (var item in p)//直至呼叫時才執行 方法內操作【 Console.WriteLine("The method was called.");】
            {
                Console.WriteLine(item);
            }
          
            Console.ReadKey();
        }
       
        public static IEnumerable<int> GetSingleDigitNumbers(int[] s)
        {
            foreach (var item in s)
            {
                if (item%2==0)
                {
                    yield return item;
                   Console.WriteLine("The method was called.");
                }              
            }
        }

結果:

總結:

  • foreach:
    * 通過 return 語句立即把程式的控制權交回給呼叫者,同時也會把方法內的本地資源釋放掉
    * 依賴於 .NET Core 庫中定義的 2 個泛型介面,才能生成迴圈訪問集合所需的程式碼:IEnumerable 和 IEnumerator
  • iterator:
    * 使用yeild return 可依次返回多個值給呼叫者的期間仍保留方法內本地資源,等所有值都返回結束時,再釋放掉方法內資源,這些返回的值形成一組序列被呼叫者使用
    * 同一方法中不能同時使用 return 語句和 yield return 語句
    * 本身僅返回一組有效值 方法內額外操作 僅在結果被呼叫時執行