码迷,mamicode.com
首页 > 其他好文 > 详细

foreach-本质

时间:2017-11-07 01:36:17      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:object   ring   错误   compile   .com   作用   分享   eal   item   

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

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

编译错误:

技术分享

也就是说我们有GetEnumerator方法才行,返回一个枚举器(foreach其它类型看反编译的代码才知道的)。这个方法我们可以继承IEnumerable接口(实际写不写都没关系)。改造一下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中自动推断出来的类型。之前我反编译过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为什么就能调用呢?查看反编译的代码:

技术分享

所以foreach其实是调用了GetEnumerator方法进行操作的,根据这里面的我们可以改写我们的代码(运行结果跟之前的一样):

            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;
    }
}

 

foreach-本质

标签:object   ring   错误   compile   .com   作用   分享   eal   item   

原文地址:http://www.cnblogs.com/entclark/p/7795968.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!