zoukankan      html  css  js  c++  java
  • 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;
        }
    }
    
  • 相关阅读:
    C语言(1)
    ​ Markdown
    多功能嵌入式解码软件(4)
    多功能嵌入式解码软件(3)
    多功能嵌入式解码软件(2)
    STM32最小系统设计
    C#通过字符串分割字符串Split
    基于串口的SD_card系统
    直流无刷电机工作原理
    Java常用函数式接口--Consumer接口使用案例
  • 原文地址:https://www.cnblogs.com/entclark/p/7795968.html
Copyright © 2011-2022 走看看