IEnumerable和IEnumerator

概述

IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能!

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}
 
public interface IEnumerator
{
    object Current { get; }
 
    bool MoveNext();
 
    void Reset();
}

迭代的原理

首先来说一下集合实现的原理:对于ArrayList、List<T>等集合,类中有一个私有的数组类型字段,向集合中添加数据时调用Add方法(将数据元素添加到私有数组字段中),而调用类的其他方法时,其实就是对私有数组类型字段的操作。

复制代码
 1 public class ArrayList : IList, ICollection, IEnumerable, ICloneable
 2 {
 3     //省略其他代码
 4     private object[] _items;
 5     
 6     public virtual int Add(object value)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size + 1);
11         }
12         this._items[this._size] = value;
13         this._version++;
14         return this._size++;
15     }
16 }
ArrayList
复制代码
复制代码
 1 public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
 2 {
 3     //省略其他代码
 4     private T[] _items;
 5     
 6     public void Add(T item)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size + 1);
11         }
12         this._items[this._size++] = item;
13         this._version++;
14     }
15 }
List
复制代码

所以对于这些集合来说,本质上集合中的所有元素都是保存在一个私有数组类型的字段中,众所周知,对于ArrayList或者List<T>都可以使用foreach进行迭代,查看集合中的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
static void Main(string[] args)
{
    List<string> strs=new List<string>();
    strs.Add("DD");
    strs.Add("FF");
    strs.Add("VV");
    strs.Add("WW");
    foreach (String str in strs)
    {
        Console.WriteLine(str);
    }
    Console.ReadKey();
}

上述这个foreach的迭代的过程是如何实现的呢?foreach为什么可以逐个遍历所以集合中的元素呢?下面我们就用IL反汇编程序来查看上述代码的foreach部分的IL!

看不懂?没关系啦,那么我们就来大致的猜想一下,我们的foreach生成了这么一大坨的IL中居然有Enumerator什么的,难道跟这个有关系吗?恰巧听说IEnumerable和IEnumrator用来实现迭代,恰恰巧我们的ArrayList、List<T>集合都是实现了IEnumerable接口。那么我们就来做的大胆的假设,foreach其实就是执行跟IEnumerable和IEnumrator接口相关的代码,并对保存集合的私有数组字段的索引进行操作,从而来实现迭代的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main(string[] args)
{
    List<string> strs=new List<string>();
    strs.Add("DD");
    strs.Add("FF");
    strs.Add("VV");
    strs.Add("WW");
    IEnumerator<string> items = strs.GetEnumerator();
    while (items.MoveNext())
    {
        Console.WriteLine(items.Current);
    }
    Console.ReadKey();
}

这段代码也同样实现了对集合元素迭代的功能!在来看一下这个迭代生成的相关IL。

嘿嘿,对比两者生成的IL,目测他们的执行过程中调用的IL指令大体上是一致的(IL指令啥的暂时我也不是很了解),所以我们的猜想应该是正确的,foreach在本质上其实就是通过ArrayList、List<T>中定义的GetEnumerator方法,以及后续的代码实现的!下面就来看看List<T>中是如何定义的。

复制代码
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    private T[] _items;
    public List<T>.Enumerator GetEnumerator()
    {
        return new List<T>.Enumerator(this);
    }
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
    {
        private List<T> list;
        private int index;
        private int version;
        private T current;
        
        public T Current
        {
            
            get
            {
                return this.current;
            }
        }
        
        object IEnumerator.Current
        {
            
            get
            {
                if (this.index == 0 || this.index == this.list._size + 1)
                {
                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
                }
                return this.Current;
            }
        }
        internal Enumerator(List<T> list)
        {
            this.list = list;
            this.index = 0;
            this.version = list._version;
            this.current = default(T);
        }
        
        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            List<T> list = this.list;
            if (this.version == list._version && this.index < list._size)
            {
                this.current = list._items[this.index];
                this.index++;
                return true;
            }
            return this.MoveNextRare();
        }
        private bool MoveNextRare()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = this.list._size + 1;
            this.current = default(T);
            return false;
        }
        
        void IEnumerator.Reset()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = 0;
            this.current = default(T);
        }
    }
}    
        
List<T>
复制代码

哇哦,原来迭代器是这样的呀!!!!

自定义一个简单的支持迭代的集合

下面我们就来自定义一个支持迭代器的集合

复制代码
public class UserDefinedCollection<T>:IEnumerable<T>
    {
        private List<T> list = new List<T>();

        public UserDefinedCollection(List<T> param)
        {
            list = param;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return new UserDefinedEnum<T>(list);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        private sealed class UserDefinedEnum<T>:IEnumerator<T>
        {
            private List<T> list = null;
            private int _CurrentIndex;
            private T _CurrentElement;

            public UserDefinedEnum(List<T> param)
            {
                this.list = param;
                this._CurrentIndex = 0;
                _CurrentElement = default(T);
                
            }

            public T Current
            {
                get 
                {
                    return _CurrentElement;
                }
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (this._CurrentIndex < this.list.Count)
                {
                    this._CurrentElement = this.list[this._CurrentIndex++];
                    return true;
                }
                return false;
            }

            public void Reset()
            {
                this._CurrentElement = default(T);
                this._CurrentIndex = 0;
            }
            public void Dispose()
            {
                
            }
        }

    }
复制代码

 测试自定义集合的迭代功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
List<string> strs=new List<string>();
strs.Add("DD");
strs.Add("FF");
strs.Add("VV");
strs.Add("WW");
UserDefinedCollection<String> user = new UserDefinedCollection<string>(strs);
IEnumerator<string> iEnumerator = user.GetEnumerator();
 
while (iEnumerator.MoveNext())
{
    Console.WriteLine(iEnumerator.Current);
}
 
foreach (String str in user)
{
    Console.WriteLine(str);
}

 

扩展:由模型绑定中,绑定泛型类型时学习到泛型相关的知识!

  



posted @   武沛齐  阅读(808)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示