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

 

posted @ 2018-04-12 20:14  诸子百家,唯我纵横  阅读(330)  评论(0编辑  收藏  举报