C#之foreach实现探秘

代码 1:        static void Main(string[] args)
        {
            int[] hs = { 1,2,3,4,5,6,7,8,9};
            foreach (int item in hs)
            {
                Console.WriteLine(item.ToString());
            }

            Console.ReadKey();
        }
代码 2:        static void Main(string[] args)
        {
            ArrayList ArrLst = new ArrayList();
            ArrLst.AddRange(new string[] { "jack","rose","joy","kristina"});

            foreach (string s in ArrLst)
            {
                Console.WriteLine(s);
            }

            Console.ReadKey();
        }

  为什么代码 1 和 代码 2可以使用foreach来循环遍历int数组的元素?

代码 3:using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ForeachDemo
{
    class Dog
    {
        //构造函数
        public Dog(params string[] dogNames)
        {
            DogNames.AddRange(dogNames);
        }
        //名称字段、属性
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        //List<string>集合元素数
        public int DogNamesCounts()
        {
            return DogNames.Count;
        }
        public List<string> DogNames = new List<string>();
        //Dog类对象所引器
        public string this[int index]
        {
            get { return DogNames[index];}
            set
            {
                if (index >= DogNames.Count)
                {
                    DogNames.Add(value);
                }
                else
                {
                    DogNames[index] = value;
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dog D = new Dog("哈士奇","吉娃娃","藏獒","牧羊犬");
            //for循环可以通过所引器访问对象
            //for (int i = 0; i < D.DogNames.Count; i++)
            //{
            //    Console.WriteLine(D[i].ToString());
            //}
            //foreach却不能通过所引器遍历
            foreach (string s in D)
            {
                Console.WriteLine(s);
            }

            Console.ReadKey();
        }
    }
}

  为什么代码 3 不可以通过foreach循环遍历呢?

  原因分析:

  • 数组(Array)实现了IEnumerable接口(公开枚举器,该枚举器支持在非泛型集合上进行简单迭代。)
  • 要想自己编写的类也具有foreach循环遍历的能力,这个类得实现IEnumerator接口(非泛型)

  那针对以上代码的修改如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ForeachDemo
{
    class Dog:IEnumerable
    {
        //构造函数
        public Dog(params string[] dogNames)
        {
            DogNames.AddRange(dogNames);
        }
        //名称字段、属性
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        //List<string>集合元素数
        public int DogNamesCounts()
        {
            return DogNames.Count;
        }
        public List<string> DogNames = new List<string>();
        //Dog类对象所引器
        public string this[int index]
        {
            get { return DogNames[index]; }
            set
            {
                if (index >= DogNames.Count)
                {
                    DogNames.Add(value);
                }
                else
                {
                    DogNames[index] = value;
                }
            }
        }
        //这里需要一个IEnumerator类型的对象返回值(显式实现IEnumerable)
        //IEnumerator IEnumerable.GetEnumerator()
        //{
        //    throw new NotImplementedException();
        //}

        public IEnumerator GetEnumerator()
        {
            return new DogEnumerator(this.DogNames);
        }
    }

    public class DogEnumerator:IEnumerator
    {
        /* 显式实现IEnumerator接口
        object IEnumerator.Current
        {
            get { throw new NotImplementedException(); }
        }

        bool IEnumerator.MoveNext()
        {
            throw new NotImplementedException();
        }

        void IEnumerator.Reset()
        {
            throw new NotImplementedException();
        }*/
        //构造函数
        public DogEnumerator(List<string> paramDogNames)
        {
            this.dogsNames = paramDogNames;
        }

        List<string> dogsNames = new List<string>();

        //枚举器初始索引
        private int index = -1;

        //获取集合中的当前元素
        public object Current
        {
            get
            {
                if (index < 0)
                {
                    return null;
                }
                else
                {
                    return dogsNames[index];
                }
            }
        }
        //判断是否可以将枚举数推进到集合的下一个元素
        public bool MoveNext()
        {
            index += 1;
            if (index >= dogsNames.Count)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        //将枚举数设置为其初始位置,该位置位于集合中第一个元素之前(索引为-1)
        public void Reset()
        {
            this.index = -1;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dog D = new Dog("哈士奇", "吉娃娃", "藏獒", "牧羊犬");

            //for循环可以通过所引器访问对象
            //for (int i = 0; i < D.DogNames.Count; i++)
            //{
            //    Console.WriteLine(D[i].ToString());
            //}

            foreach (string s in D)
            {
                Console.WriteLine(s);
            }

            Console.ReadKey();
        }
    }
}
时间: 2024-08-04 11:08:50

C#之foreach实现探秘的相关文章

优雅的 laravel(1)- Composer概述及其自动加载探秘

刚开始接触laravel,一天时间走马观花的看了一些官方文档之后便开始了laravel的学习.这里谈到的都是最基础的东西,各路大神,可直接略过. composer概述 一开始,最吸引我的当属 Composer 了,因为之前从没用过 Composer . Composer 是PHP中用来管理依赖关系的工具,你只需在自己的项目中声明所依赖的外部工具库,Composer就会帮你安装这些依赖的库文件.运行 Composer 需要 PHP 5.3.2+ 以上版本. 使用composer 第一步,声明依赖关

探秘C#中的yield关键字

在"C#中,什么时候用yield return"中,我们了解到:使用yield return返回集合,不是一次性加载到内存中,而是客户端每调用一次就返回一个集合元素,是一种"按需供给".本篇来重温yield return的用法,探秘yield背后的故事并自定义一个能达到yield return相同效果的类,最后体验yield break的用法. □ 回顾yield return的用法 以下代码创建一个集合并遍历集合. class Program { static R

Typescript : 遍历Array的方法:for, forEach, every等

方法一,for-of 这个貌似是最常用的方法,angular 2中HTML语法绑定也是要的这种语法. let someArray = [1, "string", false]; for (let entry of someArray) { console.log(entry); // 1, "string", false } for-in 官方文档上强调了for-in和for-of的区别: let list = [4, 5, 6]; for (let i in li

嘿!@野兽,你的ng api 掉了 - - angular.forEach

@野兽的 ng api 学习 -- angular.forEach angular.forEach 调用迭代器函数取每一项目标的集合,它可以是一个对象或数组.迭代器函数与迭代器(value.key)一起调用,其中值是一个对象属性或数组元素的值,而数组元素是对象属性的关键或数组元素索引.为函数指定一个可选的上下文. 格式:angular.forEach(obj,iterator,[context]); obj:遍历的对象 iterator:迭代器 [content]: 对象为迭代器函数的上下文(t

【java8】慎用java8的foreach循环

虽然java8出来很久了,但是之前用的一直也不多,最近正好学习了java8,推荐一本书还是不错的<写给大忙人看的javase8>.因为学习了Java8,所以只要能用到的地方都会去用,尤其是Java8的Stream,感觉用起来觉得很方便,因为点点点就出来了,而且代码那么简洁.现在开始慢慢深入了解java8,发现很多东西不能看表面. 比如常规遍历一个集合,下面给出例子: 1.首先遍历一个List 方式1.一开始是这样的: public static void test1(List<Strin

php中的foreach使用

foreach语句是php用来遍历数组的一种方法,主要有两种格式: 第一种:foreach (array_name as $value) 例1: <?php$arr=array(1,2,3);foreach ($arr as $key =>$value){ echo "Value: " . $value . "<br />";}?> 运行结果: 第二种:foreach  (array_name as $key => $value)

c# winform 循环遍历界面上的所有控件,foreach,Controls,AllowDrop

foreach (System.Windows.Forms.Control control in this.groupBox2.Controls)//遍历groupBox2上的所有控件 { if (control is System.Windows.Forms.PictureBox) { System.Windows.Forms.PictureBox pb = (System.Windows.Forms.PictureBox)control; pb.AllowDrop = true; } if

java中for循环的特殊:foreach的使用

首先格式是: for(元素类型 元素变量:遍历对象){ 执行的代码 } 例如: public class Test { public static void main(String[] args) { // 定义一个整型数组,保存成绩信息 int[] scores = { 89, 72, 64, 58, 93 }; // 对Arrays类对数组进行排序 Arrays.sort(scores); // 使用foreach遍历输出数组中的元素 for ( int sco:scores ) { Sys

map() 和 forEach() 区别 兼容写法

兼容写法: 不管是forEach还是map在IE6-8下都不兼容(不兼容的情况下在Array.prototype上没有这两个方法),那么需要我们自己封装一个都兼容的方法,代码如下: /** * forEach遍历数组 * @param callback [function] 回调函数: * @param context [object] 上下文: */ Array.prototype.myForEach = function myForEach(callback,context){ contex