16°

IEnumerable和IEnumerator详解

引言

IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator;IEnumerator提供通过Current属性以及MoveNext()和Reset()方法来循环访问集合的功能。

IEnumerable 接口

公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。接口源码如下:

public interface IEnumerable
{
    [DispId(-4), __DynamicallyInvokable]
    IEnumerator GetEnumerator();
}

IEnumerable 接口

支持对非泛型集合的简单迭代。接口源码如下:

public interface IEnumerator
{
    [__DynamicallyInvokable]
    bool MoveNext();
    [__DynamicallyInvokable]
    object Current { [__DynamicallyInvokable] get; }
    [__DynamicallyInvokable]
    void Reset();
}

举例说明

示例演示了通过实现IEnumerable和IEnumerator接口来循环访问自定义集合的最佳实践。

定义一个简单的实体类:

public class Person
    {
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
        public string Name;
        public int Age;
    }

定义一个实体类的集合,继承IEnumerate:

 public class People : IEnumerable
    {
        private Person[] _people;
        public People(Person[] pArray)
        {
            _people = new Person[pArray.Length];
            for (int i = 0; i < pArray.Length; i++)
            {
                _people[i] = pArray[i];
            }
        }
        /// <summary>
        /// GetEnumerator方法的实现
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public PeopleEnum GetEnumerator()
        {
            return new PeopleEnum(_people);
        }
    }

定义一个枚举器,继承IEnumerator:

public class PeopleEnum : IEnumerator
    {
        public Person[] _people;
    </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;summary&gt;</span>
    <span style="color: #808080;">///</span><span style="color: #008000;"> 枚举器位于第一个元素之前直到第一个MoveNext()调用。
    </span><span style="color: #808080;">///</span> <span style="color: #808080;">&lt;/summary&gt;</span>
    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> position = -<span style="color: #800080;">1</span><span style="color: #000000;">;
    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> PeopleEnum(Person[] list)
    {
        _people </span>=<span style="color: #000000;"> list;
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">bool</span><span style="color: #000000;"> MoveNext()
    {
        position</span>++<span style="color: #000000;">;
        </span><span style="color: #0000ff;">return</span> position &lt;<span style="color: #000000;"> _people.Length;
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> Reset()
    {
        position </span>= -<span style="color: #800080;">1</span><span style="color: #000000;">;
    }

    </span><span style="color: #0000ff;">object</span> IEnumerator.Current =&gt;<span style="color: #000000;"> Current;

    </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> Person Current
    {
        </span><span style="color: #0000ff;">get</span><span style="color: #000000;">
        {
            </span><span style="color: #0000ff;">try</span><span style="color: #000000;">
            {
                </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> _people[position];
            }
            </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (IndexOutOfRangeException)
            {
                </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> InvalidOperationException();
            }
        }
    }
}</span></pre> 

具体调用:

 Person[] peopleArray = new Person[3]
            {
                new Person("张三", 15),
                new Person("李四", 18),
                new Person("王五", 21),
            };
 People peopleList = new People(peopleArray);

foreach (Person p in peopleList) Console.WriteLine(p.Name + "\t" + p.Age);

输出:

其中,上边调用中foreach等价于

IEnumerator enumeratorSimple = peopleList.GetEnumerator();
while (enumeratorSimple.MoveNext())
   {
        Person p = enumeratorSimple.Current as Person;
        Console.WriteLine(p?.Name + "\t" + p?.Age);
   }

通过例子,可以得出:

  • 实现一个自定义集合,继承于IEnumerate,必须实现一个枚举器;
  • C# 语言的foreach语句隐藏了枚举数的复杂性,因此, 建议foreach使用, 而不是直接操作枚举器;
  • 枚举器可用于读取集合中的数据,但不能用于修改基础集合。

总结

IEnumerable代表继承此接口的类(比如ArrayList,IList,List<T>等)可以获取一个IEnumerator来实现枚举这个类中包含的集合中的元素的功能,是 .NET Framework 中最基本的集合访问器。在编程中,Lambda表达式通过Select()或者Where()返回的变量为IEnumerate<T>,此时我们可以通过foreach遍历。希望本文对你有所帮助,下一篇介绍Lambda中的Select和Where,感兴趣的朋友可以加关注,欢迎留言交流!

本文转载自博客园,原文链接:https://www.cnblogs.com/aizai846/p/11978715.html

全部评论: 0

    我有话说: