• C# foreach 底层原理分析及自定义 MyList


     foreach 在我们进行.net 开发时算是比较常见的,我们以List为例,调试一下源码。

    了解foreach内部调用机制,理解一个类需要满足什么条件才能使用foreach。

    //List定义定义 
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    //4种接口定义
    IEnumerable
        IEnumerator GetEnumerator();    
    IEnumerator
        bool MoveNext();
            object Current;
        void Reset();
    
    IEnumerable<out T> : IEnumerable
        IEnumerator<T> GetEnumerator();
    IEnumerator<out T> : IDisposable, IEnumerator
        T Current;

    0- 新建控制台程序:

        static void Main(string[] args)
        {
    
            List<int> test = new List<int> { 1, 2, 3, 4};
            foreach (var item in test)
            {
                Console.WriteLine();
            }
    
            Console.ReadKey();
        }

    1- List进行了初始化,将一个空数组赋值给了_items数组

     

    2- 然后List进行初始化的时候调用了Add方法,然后进行了扩容判断 (具体如何扩容就不贴出来了)

     3- 执行foreach的时候,调用了GetEnumerator() ,获得了一个迭代器。注意看这里的返回值是一个List<T>.Enumerator,它在List内部被定义为了一个结构体。

     

     3-1 遍历数据的时候 第一步执行 迭代器的 MoveNext方法,

    3-2 获取迭代器 Current 属性值

     

    这里我们得出一个结论,只要一个类实现了 IEnumerable 接口能够返回一个迭代器,那就可以使用foreach进行遍历。

    举一反三,我们理解了foreach原理后,模仿List 创建一个我们自己的MyList,然后可以传递Func委托过滤遍历的类(玩一玩,运用一下)

        public class MyList<T> : IEnumerable
        {
            private static readonly T[] _emptyArray = new T[0];
            private const int _defaultCapacity = 4;
            private T[] _items;
            private int _size;
            private int _version;
            private Func<T, bool> _filterFunc;
    
            public int Count => _size;
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
    
            public MyList()
            {
                this._items = _emptyArray;
            }
    
            /// <param name="func"></param>
            public MyList(Func<T, bool> func)
            {
                this._items = _emptyArray;
                _filterFunc = func;
            }
    
            public IEnumerator GetEnumerator()
            {
                return new Enumerator(this);
            }
    
            public void Add(T item)
            {
                if (this._size == this._items.Length)
                    this.EnsureCapacity(this._size + 1);
                this._items[this._size++] = item;
                ++this._version;
            }
    
            /// <summary>
            /// 扩容机制
            /// </summary>
            /// <param name="min"></param>
            private void EnsureCapacity(int min)
            {
                if (this._items.Length >= min)
                    return;
                int num = this._items.Length == 0 ? 4 : this._items.Length * 2;
                if ((uint)num > 2146435071U)
                    num = 2146435071;
                if (num < min)
                    num = min;
                this.Capacity = num;
            }
    
            public int Capacity
            {
                get => this._items.Length;
    
                set //有点子监听的感觉
                {
                    if (value == this._items.Length)
                        return;
                    if (value > 0)
                    {
                        T[] objArray = new T[value];
                        if (this._size > 0) //扩容真正实现在这里
                            Array.Copy((Array)this._items, 0, (Array)objArray, 0, this._size);
                        this._items = objArray;
                    }
                    else
                        this._items = _emptyArray;
                }
            }
    
            /// <summary>
            /// 迭代器定义
            /// </summary>
            public struct Enumerator : IEnumerator
            {
                private MyList<T> _list;
                private int _index;
                private int _version;
                private T current;
    
                internal Enumerator(MyList<T> list)
                {
                    this._list = list;
                    this._index = 0;
                    this._version = list._version;
                    this.current = default(T);
                }
    
                public bool MoveNext()
                {
                    if (this._version != _list._version || (uint)this._index >= (uint)_list._size)
                        return this.MoveNextRare();
    
                    this.current = _list._items[this._index];
                    ++this._index;
    
                    //当不满足过滤条件时,foreach遍历Current返回为空
                    if (_list._filterFunc!=null && !_list._filterFunc(this.current))
                        this.current = default(T);
    
                    return true;
                }
    
                private bool MoveNextRare()
                {
                    this._index = this._list._size + 1;
                    this.current = default(T);
                    return false;
                }
    
                public object Current => this.current;
    
                public void Reset()
                {
                    _index = 0;
                    current = default(T);
                }
            }
        }

    控制台测试程序:

        class Program
        {
            static void Main(string[] args)
            {
                MyList<int> list1 = new MyList<int>(new Func<int, bool>(m => m > 5)) {1, 6, 3, 9, 10, 2, 4};
                foreach (var item in list1)
                {
                    if (item != null)
                        Console.WriteLine(item);
                }
    
                Console.ReadKey();
            }
        }

    输出结果:(初始化MyList时 我们用了int?,  因为default<int> 默认值为0,对于后面的null判空不生效)

     最后补充一点,迭代器 MoveNext()方法返回值false时,会直接终止遍历。

  • 相关阅读:
    BeautifulSoup模块
    爬取校花网视频
    爬虫基本原理
    python学习笔记-50 使用SQLAlchemy
    python学习笔记-49 使用MySQL
    PTA天梯 L3-007 天梯地图
    VS2013 创建ASP.NET MVC 4.0 未指定的错误(异常来自HRESULT: 0x80004005(e_fail))
    动态规划--新手
    文件上传绕过
    C# → 数据库
  • 原文地址:https://www.cnblogs.com/stephenzengx/p/13998427.html
Copyright © 2020-2023  润新知