zoukankan      html  css  js  c++  java
  • C#学习笔记:foreach原理

    这篇随笔是对上一篇随笔C#关键字:yield的扩展。

    关于foreach

    首先,对于 foreach ,大家应该都非常熟悉,这里就简单的描述下。

     foreach 语句用于对实现  System.Collections.IEnumerable  或 System.Collections.Generic.IEnumerable<T> 接口的数组或对象集合中的每个元素进行循环访问,但不能用于在源集合中添加或移除项,否则可能产生不可预知的副作用。如果需要在源集合中添加或移除项,应使用 for  循环。

    foreach的原理

    foreach语句是被设计用来和可枚举类型一起使用,只要它的遍历对象是可枚举类型(实现了IEnumerable),比如数组。调用过程如下:

    1. 调用GetEnumerator()方法,返回一个IEnumerator引用。
    2. 调用返回的IEnumerator接口的MoveNext()方法。
    3. 如果MoveNext()方法返回true,就使用IEnumerator接口的Current属性获取对象的一个引用,用于foreach循环。
    4. 重复前面两步,直到MoveNext()方法返回false为止,此时循环停止。

    我们可以通过代码模拟foreach的执行过程,如下:

    static void Main()
    {
        int[] arr = { 1, 2, 3, 4, 5 }; // 声明并初始化数组。
        IEnumerator ie = arr.GetEnumerator(); // 调用可枚举类型的GetEnumerator方法获得枚举数对象。
        while (ie.MoveNext()) // 调用IEnumerator接口的MoveNext方法移到下一项。实现遍历数组。
        {
            int i = (int)ie.Current; // 调用IEnumerator接口的Current方法获取当前项。注意它返回的是object类型,需要强制转换类型。
            Console.Write("{0} ", i);
        }
        // Output: 1 2 3 4 5
        Console.ReadKey();
    }

    当然,如果使用foreach的话,就非常简单了,如下:

    static void Main()
    {
        int[] arr = { 1, 2, 3, 4, 5 }; 
        foreach (int item in arr)
        {
            Console.Write("{0} ", item);
        }
        // Output: 1 2 3 4 5
        Console.ReadKey();
    }

    接下来,再看一个复杂点的实例,如下:

    class Program
    {
        static void Main()
        {
            // Create a Tokens instance.
            Tokens f = new Tokens("This is a sample sentence.", new char[] { ' ', '-' });
    
            // Display the tokens.
            foreach (string item in f)
            {
                System.Console.WriteLine(item);
            }
            // Output:
            // This
            // is
            // a
            // sample
            // sentence.
    
            Console.ReadKey();
        }
    }
    
    public class Tokens : IEnumerable
    {
        private string[] elements;
    
        public Tokens(string source, char[] delimiters)
        {
            // The constructor parses the string argument into tokens.
            elements = source.Split(delimiters);
        }
    
        // The IEnumerable interface requires implementation of method GetEnumerator.
        public IEnumerator GetEnumerator()
        {
            return new TokenEnumerator(this);
        }
    
        // Declare an inner class that implements the IEnumerator interface.
        private class TokenEnumerator : IEnumerator
        {
            private int position = -1;
            private Tokens t;
    
            public TokenEnumerator(Tokens t)
            {
                this.t = t;
            }
    
            // The IEnumerator interface requires a MoveNext method.
            public bool MoveNext()
            {
                if (position < t.elements.Length - 1)
                {
                    position++;
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
            // The IEnumerator interface requires a Reset method.
            public void Reset()
            {
                position = -1;
            }
    
            // The IEnumerator interface requires a Current method.
            public object Current
            {
                get
                {
                    return t.elements[position];
                }
            }
        }
    }

    参考文档

    1. C#中foreach的原来
    2. http://www.cnblogs.com/mcgrady/archive/2011/11/12/2246867.html
    3. https://msdn.microsoft.com/zh-cn/library/9yb8xew9%28v=vs.110%29.aspx
  • 相关阅读:
    java语言基础1问题汇总
    java从命令行接受多个数字求和输出
    关于Django迁移出现问题
    python中在ubuntu中安装虚拟环境及环境配置
    MVC与MVT
    前端性能优化
    less、sass、stylus
    bootstrap
    Swiper4.x使用方法
    swiper
  • 原文地址:https://www.cnblogs.com/CCHUncle/p/5217217.html
Copyright © 2011-2022 走看看