C#基础知识 yield与foreach

什么时候可以使用yield的关键字来定义迭代器?

  • 迭代器的返回类型必须是IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>
  • 迭代器的入参不能包括ref或out类型的参数

首先,我们定义一个简单的遍历。

        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person { SaySome = "Hello World,I am Sheldon" });
            persons.Add(new Person { SaySome = "Hello World,I am Penny" });
            persons.Add(new Person { SaySome = "Hello World,I am Amy" });
            foreach (var item in persons)
            {
                Console.WriteLine(item.SaySome);
            }
        }

它的输出结果:

接下来,我们使用yield,来实现同样的效果。

        static void Main(string[] args)
        {
            foreach (var item in GetEnumerator())
            {
                Console.WriteLine(item.SaySome);
            }
        } 

        public static IEnumerable<Person> GetEnumerator()
        {
            yield return new Person { SaySome = "Hello World,I am Sheldon" };
            yield return new Person { SaySome = "Hello World,I am Penny" };
            yield return new Person { SaySome = "Hello World,I am Amy" };
        }

虽然,我们得到了同样的结果,但是yield到底是如何做到的?

(又是翻书,又是看msdn,终于得到了答案)

使用yield语句时,它会自动生成一个枚举器,而不是仅仅生成一个包含项的列表。

——————————————————    以上内容关于yield描述了大概    ———————————————————————

——————————————————以下内容主要说明foreach如何迭代———————————————————————

这个枚举器通过foreach调用,foreach中依次访问每一项时,就会访问这个枚举器,从而达到迭代大量数据,而无须一次把所有的数据写到内存中。

关于枚举器,我查看了system.collection.generic空间下的源码。

为了知道foreach中是如何通过枚举器来工作的。

我们来根据上面的List集合声明一个简单的枚举器

(这个枚举器,只是为了简单的说明一下问题)

public class GameMoves
    {
        private IEnumerator cross;
        private IEnumerator circle;
        public GameMoves()
        {
            cross = Cross();
            circle = Circle();
        }
        private int move = 0;
        const int MaxMoves = 9;
        public IEnumerator Cross()
        {
            while (true)
            {
                Console.WriteLine("Cross, move {0}", move);
                if (++move >= MaxMoves)
                {
                    yield break;
                }
                yield return circle;
            }
        }
        public IEnumerator Circle()
        {
            while (true)
            {
                Console.WriteLine("Circle,move{0}",move);
                if (++move>=MaxMoves)
                {
                    yield break;
                }
                yield return cross;
            }
        }
    }

重写一下Main方法

            var game = new GameMoves();
            //将枚举器设置为由game.Cross()返回的枚举器类型
            IEnumerator enumerator = game.Cross();
            //第一次调用 MoveNext()时,会调用Cross()方法,Cross()方法使用yield返回另一个枚举器
            while (enumerator.MoveNext())
            {
                //返回的值可以用Current属性访问,并设置为enumerator变量,用于下一次循环
                enumerator = enumerator.Current as IEnumerator;
            }

通过上面的例子我们能看出使用while来变向说明foreach的内部执行方式。

通过 foreach 语句或 LINQ 查询来使用迭代器方法。

foreach 循环的每次迭代都会调用迭代器方法。 迭代器方法运行到 yield return 语句时,会返回一个 expression,并保留当前在代码中的位置。 下次调用迭代器函数时,将从该位置重新开始执行。

(部分源自msdn)

时间: 2024-11-01 12:49:26

C#基础知识 yield与foreach的相关文章

【ruby】ruby基础知识

Install Ruby(安装) For windows you can download Ruby from http://rubyforge.org/frs/?group_id=167 for Linux tryhttp://www.rpmfind.net. Our first program(从此开始) Enter the following into the file, "test.rb". ? 1 puts "Howdy!" At the C: promp

JavaSe基础知识总结

Java基础知识总结 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思路体现出来. 学习新技术的四点: 1,该技术是什么? 2,该技术有什么特点(使用注意): 3,该技术怎么使用.demo 4,该技术什么时候用?test. -------------------------------------------------------------------------

C#基础知识简单梳理

C#基础知识简单梳理 本文是转发博友的总结,方便自己以后随时温习: 1.值类型和引用类型 1.1堆和栈 简单的说值类型存放在堆栈上面,引用类型的数据存放在托管堆上面(它的引用地址却存放在堆栈上面)! 栈:它是一个内存数组,是一个先进后出的数据结构! 栈的特征:数据只能从栈顶进,从栈顶出! 堆:它是一个内存区域,可以分配大块区域存储某类型的数据,与栈不同的是它里面的数据可以任意排序和移除! 下面是园子的一张图,贴上来供大家参考啊! 问     题 值  类  型 引 用 类 型 这个类型分配在哪里

毕向东—Java基础知识总结(超级经典)

Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思路体现出来. 学习新技术的四点: 1,该技术是什么? 2,该技术有什么特点(使用注意): 3,该技术怎么使用.demo 4,该技术什么时候用?test. ------------------------------------------------------ 一:java概述: 19

Java基础知识总结(超级经典)

Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java语言代码把思路体现出来. 学习新技术的四点: 1,该技术是什么? 2,该技术有什么特点(使用注意): 3,该技术怎么使用.demo 4,该技术什么时候用?test. —————————————————————————————————————————————————————— 一:java概述: 19

Java基础知识整理(一)

概述 公司业务需要,产品既要有.NET又需要Java,没得选择,只能业余时间学习Java,整体觉得Java也.NET还是很相似的,只是语法有差别,差别也不是很大,这就将学习Java的基础知识整理下,以便于自己的学习.作为个.NET程序猿也可以学习Java ,毕竟技多不压身,学习多也要精通. 开发工具 eclipse ,开发java类似.NET 需要装JDK类似.NET Framework. Java开发工具eclipse设置 1.设置字体:window设置: 2.设置快捷键:window--ke

C#基础知识篇(二)-----------C#笔记

1.关系运算符(比较运算符) 1.关系运算符有哪些? >,< ==,!= >=,<= 2.关系运算符的作用? 用于比较两个事物之间的关系. 3.什么叫关系表达式? 由关系运算符连接起来的式子叫关系表达式. 注意:所有的关系表达式最终都能计算成一个bool类型的值. 2.逻辑运算符 1.逻辑表达式有哪些? 逻辑与:&& ,逻辑或:||  ,逻辑非:!(又叫取反) 2.逻辑运算 语法:表达式1 逻辑运算符  表达式2 逻辑运算符连接的两个表达式,要最终能求解成一个boo

JS基础知识回顾:引用类型(一)

在ECMAScript中引用类型是一种数据结构,用于将数据和功能组织在一起,而对象时引用类型的一个实例. 尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构,所以虽然说引用类型与类看起来想死,但他们并不是相同的概念. 不过引用类型有的时候也可以被称为对象定义,因为他们描述的是一类对象所具有的属性和方法. 新对象是使用new操作符后跟一个构造函数来实现的,构造函数本身就是一个函数,只不过该函数时处于创建新对象的目的而定义的. ECMASc

PHP基础入门(四)---PHP数组实用基础知识

PHP数组 数组是特殊的变量,它可以同时保存一个以上的值. ***关键词:数组基础.数组遍历.超全局数组.数组功能.数组函数. 下面来和大家分享一下有关PHP的数组基础知识,希望对你PHP的学习有所帮助~ 一.PHP数组基础部分 一PHP数组的分类 按照下标的不同,PHP数组分为关联数组和索引数组:索引数组:下标从0开始,依次增长关联数组:下标为字符串格式,每个下标字符串与数组的值一一关联对应(类似对象的键值对) 代码演示: 1 $arr1 = array(1,2,3,4,5,6,7);//索引