首页 > 代码库 > yield个人理解及简明示例

yield个人理解及简明示例

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