zoukankan      html  css  js  c++  java
  • foreach 的本质

    实现foreach循环先满足IEnumerable接口IEnumerator 是所有非泛型枚举数的基接口。

    IEnumerator 接口 支持对非泛型集合的简单迭代。

    C# 语言的 foreach 语句(在 Visual Basic 中为 for each)隐藏了枚举数的复杂性。

    枚举数可用于读取集合中的数据,但不能用于修改基础集合。

    最初,枚举数定位在集合中第一个元素前。Reset 方法还会将枚举数返回到此位置。在此位置,调用 Current 属性会引发异常。因此,在读取 Current 的值之前,必须调用 MoveNext 方法将枚举数提前到集合的第一个元素。

    在调用 MoveNext 或 Reset 之前,Current 返回同一对象。MoveNext 将 Current 设置为下一个元素。

    如果 MoveNext 越过集合的末尾,则枚举数将被放置在此集合中最后一个元素的后面,而且 MoveNext 返回 false。当枚举数位于此位置时,对 MoveNext 的后续调用也返回 false。如果最后一次调用 MoveNext 返回 false,则调用 Current 会引发异常。若要再次将 Current 设置为集合的第一个元素,可以调用 Reset,然后再调用 MoveNext。

    只要集合保持不变,枚举数就保持有效。如果对集合进行了更改(如添加、修改或删除元素),则枚举数将失效且不可恢复,并且下一次对 MoveNext 或 Reset 的调用将引发 InvalidOperationException。如果在 MoveNext 和 Current 之间修改集合,那么即使枚举数已经无效,Current 也将返回它所设置成的元素。

    枚举数没有对集合的独占访问权;因此,枚举通过集合在本质上不是一个线程安全的过程。即使一个集合已进行同步,其他线程仍可以修改该集合,这将导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。

    namespace ConsoleApplication1
    {
        public class Person
        {
            public string firstName;
            public string lastName;
    
            public Person(string fName, string lName)
            {
                this.firstName = fName;
                this.lastName = lName;
            }
        }
    
        public class People : IEnumerable
        {
            private Person[] _people;
            public People(Person[] pArray)
            {
                _people = new Person[pArray.Length];
    
                for (int i = 0; i < pArray.Length; i++)
                {
                    _people[i] = pArray[i];
                }
            }
    
            public IEnumerator GetEnumerator()
            {
                return new PeopleEnum(_people);
    
            }
        }
    
    
        public class PeopleEnum : IEnumerator
        {
            public Person[] _people;
    
            // Enumerators are positioned before the first element
            // until the first MoveNext() call.
    
            int position = -1;
    
            public PeopleEnum(Person[] list)
            {
                _people = list;
            }
    
            public bool MoveNext()
            {
                position++;
                return (position < _people.Length);
            }
    
            public void Reset()
            {
                position = -1;
            }
    
            public object Current
            {
                get
                {
                    try
                    {
                        return _people[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }
    
    
        public class DogEnum : IEnumerator
        {
    
            #region IEnumerator 成员
    
            public object Current
            {
                get { throw new NotImplementedException(); }
            }
    
            public bool MoveNext()
            {
                throw new NotImplementedException();
            }
    
            public void Reset()
            {
                throw new NotImplementedException();
            }
    
            #endregion
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Person[] peopleArray = new Person[3]
                {
                    new Person("John", "Smith"),
                    new Person("Jim", "Johnson"),
                    new Person("Sue", "Rabon")
                };
    
                People peopleList = new People(peopleArray);
    
                //foreach
                foreach (Person p in peopleList)
                {
                    Console.WriteLine(p.firstName + " " + p.lastName);
                }
    
                //foreach本质上是这样调用的
                IEnumerator myrator = peopleList.GetEnumerator();
                myrator.Reset();
                while (myrator.MoveNext())
                {
                    Person p = (Person)myrator.Current;
                    Console.WriteLine(p.firstName + " " + p.lastName);
                }
            }
        }
    }
    View Code

    返回迭代器yield

    class App
    {
        class Product
        {
            public string ProductName
            { get; set; }
            public decimal? ProductPrice  //decimal? 可空类型null
            { get; set; }
        }
    
        static void Main()
        {
            Product[] ps = { 
                new Product{ ProductName="iPone6", ProductPrice=3000},
                new Product{ProductName="iPone7", ProductPrice=3400},
                new Product{ProductName="iPone8", ProductPrice=5500},
                new Product{ProductName="iPoneX", ProductPrice=8000},
            };
    
            //用yield的写法
            var psList = GetCheaperPhone(ps);
    
            //用Linq的写法
            //var psList = from po in ps
            //           where po.ProductPrice <= 3500
            //           select po;
    
            //输出满足条件的集合
            foreach (var p in psList)
            {
                Console.WriteLine(p.ProductName + ":" + p.ProductPrice);
            }
    
            
    
        }
        //普通List写法
        //private static IEnumerable<Product> GetCheaperPhone(Product[] ps)
        //{
        //    List<Product> pianyihuo = new List<Product>();//先申明一个装商品的集合
        //    for (int i = 0; i < ps.Length; i++)
        //    {
        //        if (ps[i].ProductPrice <= 3500)
        //        {
        //            pianyihuo.Add(ps[i]);
        //        }
        //    }
        //    return pianyihuo;
        //}
    
        private static IEnumerable<Product> GetCheaperPhone(Product[] ps)
        {
            for (int i = 0; i < ps.Length; i++)
            {
                if (ps[i].ProductPrice <= 3500)
                {
                    yield return ps[i];
                }
            }
        }
    
    }
    View Code
  • 相关阅读:
    maven问题
    用例图中三种关系详解(转)
    UML系列图--用例图
    Visio画UML用例图没有include关系的解决方法
    Linux中环境变量文件及配置
    如何开启ubuntu的SSH服务(不要和openssl搞混淆了)
    linux下的gedit命令使用方法与技巧
    ubuntu安装mysql5.7
    通过 HTTP 头进行 SQL 注入
    Redis各种数据结构内存占用测试
  • 原文地址:https://www.cnblogs.com/zzbj-wwzh/p/8780394.html
Copyright © 2011-2022 走看看