C#中的yield可以應用在一個可迭代的方法中,我們必須真正理解此關鍵詞,才能將它正確的應用到實際生產中。為了說明yield會出現讓我們迷惑的結果,下面先定義一個MyObject類:
1 class MyObject 2 { 3 public int Value{get;set;} 4 }
MyObject類用於存放一個值,下面定義一個IEnumerable<MyObject>的方法:
1 IEnumerable<MyObject> GetYieldObjects() 2 { 3 for (int i = 0; i < 10; i++) 4 { 5 Console.WriteLine("GetObjects() i="+i.ToString()); 6 yield return new MyObject() { Value = i }; 7 } 8 }
方法中用yield return返回實例化的MyObject對象,為了便於記錄GetYieldObjects()方法實際調用的過程,這裡用Console.WriteLine來記錄每次調用的過程。下面聲明一個objects對象,然後進行第一次迭代,在第一次迭代過程中,對每個迭代項目的值進行+10處理,然後進行第2此迭代,看看是否會將處理後的值進行輸出:
1 //此時不調用GetObjects()的內部循環 2 var objects = GetYieldObjects(); 3 //每次迭代會調用GetObjects()對應i的內容 4 foreach (var item in objects) 5 { 6 Console.WriteLine("1 foreach (var item in objects) item.Value=" + item.Value.ToString());//0..9 7 item.Value += 10; 8 } 9 //每次迭代會調用GetObjects()對應i的內容 10 foreach (var item in objects) 11 { 12 Console.WriteLine("2 foreach (var item in objects) item.Value=" + item.Value.ToString());//0..9 13 Console.WriteLine(item.Value.ToString());//0..9 14 }
在第2次迭代時,輸出的還是0到9,並不是10到19.請看下面的迭代過程:
當第一次迭代時候,每次迭代會調用GetObject()方法中的yield return語句,而不是在var objects=GetObjects()進行實例化。當yield取到一個MyObject對象後立刻返回給迭代器,並將其值進行輸出,然後繼續調用GetObjects方法中的yield return語句,
因此每次循環時,實際上都是一個新的對象。如下圖所示:
當然如果將上面的代碼稍作修改,用objects=GetYieldObjects().ToArray()的話,那麼第二次輸出的就是10到19:
1 objects = GetYieldObjects().ToArray(); 2 foreach (var item in objects) 3 { 4 item.Value += 10; 5 } 6 7 foreach (var item in objects) 8 { 9 Console.WriteLine(item.Value.ToString());//10..19 10 }