欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

IEnumerable和IEnumerator详解

程序员文章站 2022-06-29 14:04:12
IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator;IEnumerator提供通过Current属性以及MoveNext()和Reset()方法来循环访问集合的功能。 ... 支持对非泛型集合的简单迭代。接口源码如下: 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]; } } /// /// getenumerator方法的实现 /// /// ienumerator ienumerable.getenumerator() { return getenumerator(); } public peopleenum getenumerator() { return new peopleenum(_people); } } 定义一个枚举器,继承ienumerator: public class peopleenum : ienumerator { public person[] _people; /// /// 枚举器位于第一个元素之前直到第一个movenext()调用。 /// private int position = -1; public peopleenum(person[] list) { _people = list; } public bool movenext() { position++; return position < _people.length; } public void reset() { position = -1; } object ienumerator.current => current; public person current { get { try { return _people[position]; } catch (indexoutofrangeexception) { throw new invalidoperationexception(); } } } } 具体调用: 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等)可以获取一个ienumerator来实现枚举这个类中包含的集合中的元素的功能,是 .net framework 中最基本的集合访问器。在编程中,lambda表达式通过select()或者where()返回的变量为ienumerate,此时我们可以通过foreach遍历。希望本文对你有所帮助,下一篇介绍lambda中的select和where,感兴趣的朋友可以加关注,欢迎留言交流!...

引言

ienumerable是可枚举的所有非泛型集合的基接口, ienumerable包含一个方法getenumerator(),该方法返回一个ienumerator;ienumerator提供通过current属性以及movenext()和reset()方法来循环访问集合的功能。

ienumerable 接口

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

public interface ienumerable
{
    [dispid(-4), __dynamicallyinvokable]
    ienumerator getenumerator();
}

ienumerator 接口

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

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;

        /// <summary>
        /// 枚举器位于第一个元素之前直到第一个movenext()调用。
        /// </summary>
        private int position = -1;
        public peopleenum(person[] list)
        {
            _people = list;
        }

        public bool movenext()
        {
            position++;
            return position < _people.length;
        }

        public void reset()
        {
            position = -1;
        }

        object ienumerator.current => current;

        public person current
        {
            get
            {
                try
                {
                    return _people[position];
                }
                catch (indexoutofrangeexception)
                {
                    throw new invalidoperationexception();
                }
            }
        }
    }

具体调用:

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

输出:

IEnumerable和IEnumerator详解

其中,上边调用中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,感兴趣的朋友可以加关注,欢迎留言交流!