从foreach语句枚举元素看数组

在foreach语句中使用枚举,可以迭代数组或集合中的元素,且无须知道集合中的元素的个数。如图显示了调用foreach方法的客户端和集合之间的关系。数组或集合实现带GetEnumerator()方法的IEnumerable接口。GetEnumerator()方法返回一个实现lEnumerable接口的枚举,接着foreach语句就可以使用IEnumerable接口迭代集合了。

GetEnumerator()方法用IEnumerable接口定义,foreach语句并不真的需要在集合类中实现这个接口。有一个名为GetEnumerator()的方法它返回实现了IEnumerator接口的对象就足够了。

先定义一个Person类,这个类有自动实现的属性Firstname和Lastname,以及从Object类重写ToString方法和继承泛型接口IEquatable以比较两个对象是否相等,实现泛型接口IComparer以比较两个对象用来排序。

public class Person : IEquatable<Person>,IComparable<Person>
    {
        public int Id { get; private set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public override string ToString()
        {
            return String.Format("{0}, {1} {2}", Id, FirstName, LastName);
        }   

        public bool Equals(Person other)
        {
            if (other == null)
                return base.Equals(other);

            return this.FirstName == other.FirstName && this.LastName == other.LastName;
        }

        public int CompareTo(Person other)
        {
            if (other == null) throw new ArgumentNullException("other");

            int result = this.LastName.CompareTo(other.LastName);
            if (result == 0)
            {
                result = this.FirstName.CompareTo(other.FirstName);
            }

            return result;
        }

    }

创建一个三个元素的person数组,现对数组进行排序在用foreach循环访问数组中的元素并输出

 Person[] persons = {
                new Person { FirstName = "Simen03", LastName = "Go" },
                new Person { FirstName = "Simen02", LastName = "Go" },
                new Person { FirstName = "Simen01", LastName = "Go" }
            };
            Array.Sort(persons);
            foreach (var person in persons)
                Console.WriteLine(person);

分析foreach (var person in persons)Console.WriteLine(person);这段代码IL代码

// loop start (head: IL_009b)
            IL_008a: ldloc.2
            IL_008b: ldloc.3
            IL_008c: ldelem.ref
            IL_008d: stloc.s person
            IL_008f: ldloc.s person
            IL_0091: call void [mscorlib]System.Console::WriteLine(object)
            IL_0096: nop
            IL_0097: ldloc.3
            IL_0098: ldc.i4.1
            IL_0099: add
            IL_009a: stloc.3

            IL_009b: ldloc.3
            IL_009c: ldloc.2
            IL_009d: ldlen
            IL_009e: conv.i4
            IL_009f: blt.s IL_008a
        // end loop

C#的foreach语句不会解析为IL代码中的foreach语句,C#编译器会把foreach语句转换为IEnumerable接口的方法和属性,foreach语句使用IEnumerator接口的方法和属性,迭代数组中的所有元素,为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到数组的下一个元素上,如果有这个元素该方法就返回true否则返回false,这个接口的泛型版本IEnumerator派生自接口IDisposable,因此定义了Dispose()方法来清理枚举器占用的资源,使用foreach语句会解析为下面的代码段

 IEnumerator enumerator = persons.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var person = enumerator.Current;
                Console.WriteLine(person);
            }

为了方便的创建枚举器,C#添加了yield语句,yield return 语句返回集合的一个元素,并移动到下一个元素,yield break 可停止迭代。使用迭代块,编译器会生成一个yield类型,其中包含一个状态机,如下代码段所示。yield 类型实现IEnumerator和IDisposable接口的属性和方法。在下面的例子中,可以把yield类型看作内部类Enumerator.外部类的GetEnumerator()方法实例化并返回一个新的yield类型。在yield类型中,变量state定义了迭代的当前位置,每次调用MoveNext()时,当前位置都会改变,MoveNext()封装了迭代代码,并设置了current变量的值,从而使Current属性根据位置返回一个对象。

 static void Main(string[] args)
        {
            var helloCollection = new HelloCollection();
            foreach (string s in helloCollection)
            {
                Console.WriteLine(s);
            }
        }

        public class HelloCollection
        {
            public IEnumerator<string> GetEnumerator()
            {
                yield return "Hello";
                yield return "World";
            }
        }
        public class HelloCollectionOther
        {
            public IEnumerator GetEnumertor()
            {
                return new Enumerator(0);
            }
            public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable
            {
                private int state;
                private string current;
                public Enumerator(int state)
                {
                    this.state = state;
                }

                public string Current => throw new NotImplementedException();

                object IEnumerator.Current
                {
                    get { return current; }
                }

                public void Dispose()
                {
                    throw new NotImplementedException();
                }

                public bool MoveNext()
                {
                    switch (state)
                    {
                        case 0:current = "hello";
                            state = 1;
                            return true;
                        case 1:current = "world";
                            state = 2;
                            return true;
                        case 2:
                            break;
                    }
                    return false;
                }

                public void Reset()
                {
                    throw new NotImplementedException();
                }
            }
        }
时间: 2024-10-12 15:49:50

从foreach语句枚举元素看数组的相关文章

2017-9-17C#笔记(方法,方法参数 ,foreach语句)

方法: 方法作为类中最常见的最有用的一个成员,算是完成特定任务,实现特定任务的重要的编程模式. "更少的代码,更多的复用" (有些教程中,将方法称为函数,函数和方法没有本质的区别,但是通常自己写的俄实现特定的功能的代码块,叫做方法;有系统简介或者直接生成的不完整的代码块叫做函数.) 方法定义的一般形式: Static      返回类型         方法名(形式参数列表) { 声明部分 执行部分 } 事例1:编写方法判断一个数是否是完全数:完全数的定义如下:它所有的真因子(即除了自

C#通过foreach语句搜索数组元素的代码

内容过程中,将内容过程中常用的内容做个备份,下面的内容段是关于C#通过foreach语句搜索数组元素的内容,希望能对小伙伴们有所用途. using System; public class Search { public static void Main() { int[] nums = new int[10]; int val; bool found = false; for(int i = 0; i < 10; i++) nums[i] = i; val = 5; foreach(int x

为什么数组没有实现Iterable接口,但可以使用foreach语句遍历

在Java中,对于数组为什么能够使用foreach语句一直感觉很困惑. 对于能够使用foreach语句进行遍历的对象,只有两种情况,其中一种是遍历对象必须实现Iterable接口,实现ierator()方法,这是对象使用foreach语句的前提.另外一种情况就是特殊对象数组.那么对于数组可以使用foreach该如何去理解呢? 首先需要说明的是,实现了java.lang.Iterable接口的对象可以用for-each去遍历,但是能用for-each去遍历的不一定实现了该接口,比如数组这个特殊对象

C#使用foreach语句遍历数组的代码

下面的内容内容是关于C#使用foreach语句遍历数组的内容,希望对大家有所好处. using System; public class w3demo { public static void Main() { int sum = 0; int[] nums = new int[10]; for(int i = 0; i < 10; i++) nums[i] = i; foreach(int x in nums) { Console.WriteLine("Value is: "

foreach语句

foreach语句他无非就是for循环的封装,为了提高开发速度才创造出来的.他其实跟for循环一样,只不过写起来比较简便,他是1.5版本才出来的一种封装语法.并没有什么奇特之处他里面的机制就是for循环.如图7.3所示: 图7.3 首先放在冒号后面的,他可以是数组的类型也可以是集合类型还可以是枚举类型,也就是说只要写上类似于这种容器,能够容乃多个的就是行. 那这个i是什么意思呢?每次循环的时候,i他取出一个值交给变量j,变量j就是接收者,接收从数组或者集合里拿出来的值交给接收者,每次循环重新接收

foreach 语句

foreach  语句很适合用来枚举   如数组.列表.集合之类的数据结构中的元素.  不必准确知道元素个数.如果基数据不包含任何元素,则foreach循环不执行 foreach(<元素>in<基础数据>) { <代码块> } \ 首先create  一个 int型 数组,然后通过foreach循环打印出所有的数.

foreach语句揭秘

1概述 本文通过手动实现迭代器来了解foreach语句的本质. 2 使用foreach语句遍历集合 在C#中,使用foreach语句来遍历集合.foreach语句是微软提供的语法糖,使用它可以简化C#内置迭代器的使用复杂性.编译foreach语句,会生成调用GetEnumerator和MoveNext方法以及Current属性的代码,这些方法和属性恰是C#内置迭代器所提供的.下面将通过实例来说明这一切. 例1 使用foreach来遍历集合 //**************************

Java Foreach语句使用总结

foreach语句是java5的新特征之一,在遍历数组.集合方面,foreach为开发人员提供了极大的方便. foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本. foreach并不是一个关键字,习惯上将这种特殊的for语句格式称之为"foreach"语句.从英文字面意思理解foreach也就是"for 每一个"的意思.实际上也就是这个意思. foreach的语句格式

Java--分支语句、循环、数组、控制台输入语句、常用数学函数

**-----本章节-----** 1.分支语句 2.循环 3.数组 4.控制台输入语句 5.部分常用的数学函数 ============================================================== 一分支语句 1.概念 (1)分支语句又称条件语句条件语句使部分程序可根据某些表达式的值被有选择地执行. (2)Java编程语言支持双路 if和多路 switch 分支语句. ===========================================