foreach-本质

为什么可以foreach呢?我们自定义的类能不能foreach?下面请看测试

         Person p = new Person();
            foreach (string item in p)
            {
                Console.WriteLine(item);
            }
            Console.WriteLine("ok");
            Console.ReadKey();

编译错误:

也就是说我们有GetEnumerator方法才行,虽然编译错误,我们先反编译一下看看foreach最终会编译成什么?

看到了吧,foreach会生成的代码是需要一个方法GetEnumerator方法返回一个枚举器, 改造一下Person类:

 public class Person : IEnumerable
    {
        private string[] Friends = new string[] { "name0", "name2", "name3", "name4" };

        public string Name
        {
            get;
            set;
        }
        public int Age
        {
            get;
            set;
        }
        public string Email
        {
            get;
            set;
        }

        #region IEnumerable 成员

        //这个方法的作用就是返回一个“枚举器”
        public IEnumerator GetEnumerator()
        {
            return new PersonEnumerator(this.Friends);
        }

        #endregion
}
   public class PersonEnumerator : IEnumerator
    {
        public PersonEnumerator(string[] fs)
        {
            _friends = fs;
        }
        private string[] _friends;

        //一般下标都是一开始指向了第一条的前一条。
        private int index = -1;


        #region IEnumerator 成员
 
//着重说明,这个返回值类型,是我们用foreach中var自动推断出来的类型。之前我反编译过foreach Hashtable的代码看过。 public object Current { get { if (index >= 0 && index < _friends.Length) { return _friends[index]; } else { throw new IndexOutOfRangeException(); } } } public bool MoveNext() { if (index + 1 < _friends.Length) { index++; return true; } return false; } public void Reset() { index = -1; } #endregion }

再次运行:

=============================================================

综上所述,写foreach的效果跟下面的代码一样:

            Person p = new Person();
            IEnumerator etor = p.GetEnumerator();
            while (etor.MoveNext())
            {
                Console.WriteLine(etor.Current.ToString());
            }

当然了,如果我们自己写一个枚举器比较麻烦,可利用yield关键字编译器会自动生成,那就改造一下GetEnumerator方法,

 public IEnumerator<string> GetEnumerator()
        {
            for (int i = 0; i < Friends.Length; i++)
            {
                yield return Friends[i];
            }
            
        }

  结果跟之前的运行一样,我们反编译一下代码看看:

public class Person
{
    private string[] Friends = new string[] { "name0", "name2", "name3", "name4" };

    public IEnumerator<string> GetEnumerator()
    {
        for (int i = 0; i < this.Friends.Length; i++)
        {
            yield return this.Friends[i];
        }
    }

    public int Age { get; set; }

    public string Email { get; set; }

    public string Name { get; set; }

    [CompilerGenerated]
    private sealed class <GetEnumerator>d__0 : IEnumerator<string>, IEnumerator, IDisposable
    {
        private int <>1__state;
        private string <>2__current;
        public Program.Person <>4__this;
        public int <i>5__1;

        [DebuggerHidden]
        public <GetEnumerator>d__0(int <>1__state)
        {
            this.<>1__state = <>1__state;
        }

        private bool MoveNext()
        {
            switch (this.<>1__state)
            {
                case 0:
                    this.<>1__state = -1;
                    this.<i>5__1 = 0;
                    while (this.<i>5__1 < this.<>4__this.Friends.Length)
                    {
                        this.<>2__current = this.<>4__this.Friends[this.<i>5__1];
                        this.<>1__state = 1;
                        return true;
                    Label_0052:
                        this.<>1__state = -1;
                        this.<i>5__1++;
                    }
                    break;

                case 1:
                    goto Label_0052;
            }
            return false;
        }

        [DebuggerHidden]
        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        void IDisposable.Dispose()
        {
        }

        string IEnumerator<string>.Current =>
            this.<>2__current;

        object IEnumerator.Current =>
            this.<>2__current;
    }
}
原文地址:https://www.cnblogs.com/entclark/p/7795968.html