標籤:class blog http tar ext com
1.寫法有2種:
yield return <expression>和yield break
yield用於在迭代中返回一個值,並將值帶入下一次迭代中。yield break則意味著停止迭代。純粹的文字描述,一千個人有一千個說法,還是用代碼更容易說清楚。
2.官方樣本(略帶修改):
private void button1_Click(object sender, EventArgs e) { string s = string.Empty; foreach (int i in List.Power(2,8)) { s += i.ToString() + ","; } MessageBox.Show(s); } public class List { //using System.Collections; public static IEnumerable Power(int number, int exponent) { int counter = 0; int result = 1; while (counter++ < exponent) { result = result * number; yield return result; } } }
運行樣本,發現power方法中的while代碼部分,每迴圈執行一次,即輸出一個值,並將這個值帶入下一次迴圈,而power函數並沒有每次被調用。
為了驗證,我們修改下官方範例程式碼,來看看我們的判斷是否有誤:
private void button1_Click(object sender, EventArgs e) { string s = string.Empty; foreach (int i in List.Power()) { s += i.ToString() + ","; } MessageBox.Show(s); } public static IEnumerable Power() { int counter = 0; int result = 1; int number = 2, exponent = 8; while (counter++ < exponent) { result = result * number; yield return result; } }
運行結果與官方樣本相同,說明.net framework每次只把yield部分所在的部分代碼進行了迭代返回處理。
3.官方的另一個樣本為用yield作為屬性(輸出方式略有修改)。
private void button2_Click(object sender, EventArgs e) { var theGalaxies = new Galaxies(); string ps = string.Empty; foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy) { ps += (theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString() + " >> "); } MessageBox.Show(ps); } public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy { get { yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 }; yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 }; yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 }; yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 }; } }
輸出結果:
從這個例子可以看出yield其實就是臨時中斷執行,輸出後繼續執行而已。
可以修改下這個例子,看效果如何:
public class Galaxies { List<Galaxy> ls = new List<Galaxy>(); public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy { get { yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 }; yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 }; yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 }; yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 }; } } public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy1 { get { ls.Add(new Galaxy { Name = "Tadpole", MegaLightYears = 400 }); ls.Add(new Galaxy { Name = "Pinwheel", MegaLightYears = 25 }); ls.Add(new Galaxy { Name = "Milky Way", MegaLightYears = 0 }); ls.Add(new Galaxy { Name = "Andromeda", MegaLightYears = 3 }); int i = -1; while (i++ < ls.Count - 1) { yield return ls[i]; } } } }
調用NextGalaxy1後,結果與官方樣本結果相同,還可以進一步修改NextGalaxy1,使其更容易別理解:
public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy1 { get { ls.Add(new Galaxy { Name = "Tadpole", MegaLightYears = 400 }); ls.Add(new Galaxy { Name = "Pinwheel", MegaLightYears = 25 }); ls.Add(new Galaxy { Name = "Milky Way", MegaLightYears = 0 }); ls.Add(new Galaxy { Name = "Andromeda", MegaLightYears = 3 }); int i = 0; while (i < ls.Count) { yield return ls[i]; i++; } } }
這樣看來就很容易理解其含義了,更進一步說就是一邊給你輸出結果,一邊繼續給你執行代碼,一舉兩得!
如果想中斷執行,則直接用yield break即可。
代碼如下:
public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy1 { get { ls.Add(new Galaxy { Name = "Tadpole", MegaLightYears = 400 }); ls.Add(new Galaxy { Name = "Pinwheel", MegaLightYears = 25 }); ls.Add(new Galaxy { Name = "Milky Way", MegaLightYears = 0 }); ls.Add(new Galaxy { Name = "Andromeda", MegaLightYears = 3 }); int i = -1; while (i++ < ls.Count - 1) { yield return ls[i]; if (ls[i].MegaLightYears == 0) { yield break; } } } }
輸出結果為:
附官方連結:http://msdn.microsoft.com/zh-cn/library/9k7k7cf0.aspx