当前位置: 移动技术网 > IT编程>开发语言>c# > C#中foreach实现原理详解

C#中foreach实现原理详解

2019年07月18日  | 移动技术网IT编程  | 我要评论
本文主要记录我在学习c#中foreach遍历原理的心得体会。 对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如c#中的f

本文主要记录我在学习c#中foreach遍历原理的心得体会。

对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如c#中的foreach。经常会看到下面的遍历代码:

var lststr = new list<string> { "a", "b" };
   foreach (var str in lststr)
      {
        console.writeline(str);
      }

实际此代码的执行过程:

var lststr = new list<string> {"a", "b"};
   ienumerator<string> enumeratorlst = lststr.getenumerator();
   while (enumeratorlst.movenext())
      {
        console.writeline(enumeratorlst.current);
      }

会发现有getenumerator()方法和ienumerator<string>类型,这就涉及到可枚举类型和枚举器的概念。

为了方便理解,以下为非泛型示例:

// 摘要:
//   公开枚举器,该枚举器支持在非泛型集合上进行简单迭代。
  public interface ienumerable
  {
    // 摘要:
    //   返回一个循环访问集合的枚举器。
    //
    // 返回结果:
    //   可用于循环访问集合的 system.collections.ienumerator 对象。
    ienumerator getenumerator();
  }

实现了此接口的类称为可枚举类型,是可以用foreach进行遍历的标志。

方法getenumerator()的返回值是枚举器,可以理解为游标。

// 摘要:
//   支持对非泛型集合的简单迭代。
  public interface ienumerator
  {
    // 摘要:
    //   获取集合中的当前元素。
    //
    // 返回结果:
    //   集合中的当前元素。
    //
    // 异常:
    //  system.invalidoperationexception:
    //   枚举数定位在该集合的第一个元素之前或最后一个元素之后。
    object current { get; }

    // 摘要:
    //   将枚举数推进到集合的下一个元素。
    //
    // 返回结果:
    //   如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。
    //
    // 异常:
    //  system.invalidoperationexception:
    //   在创建了枚举数后集合被修改了。
    bool movenext();
    //
    // 摘要:
    //   将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
    //
    // 异常:
    //  system.invalidoperationexception:
    //   在创建了枚举数后集合被修改了。
    void reset();
  }

以下是自定义一个迭代器的示例():

using system;
using system.collections;

// simple business object.
public class person
{
  public person(string fname, string lname)
  {
    this.firstname = fname;
    this.lastname = lname;
  }

  public string firstname;
  public string lastname;
}

// collection of person objects. this class
// implements ienumerable so that it can be used
// with foreach syntax.
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];
    }
  }

// implementation for the getenumerator method.
  ienumerator ienumerable.getenumerator()
  {
    return (ienumerator) getenumerator();
  }

  public peopleenum getenumerator()
  {
    return new peopleenum(_people);
  }
}

// when you implement ienumerable, you must also implement ienumerator.
public class peopleenum : ienumerator
{
  public person[] _people;

  // enumerators are positioned before the first element
  // until the first movenext() call.
  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
  {
    get
    {
      return current;
    }
  }

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

class app
{
  static void main()
  {
    person[] peoplearray = new person[3]
    {
      new person("john", "smith"),
      new person("jim", "johnson"),
      new person("sue", "rabon"),
    };

    people peoplelist = new people(peoplearray);
    foreach (person p in peoplelist)
      console.writeline(p.firstname + " " + p.lastname);

  }
}

/* this code produces output similar to the following:
 *
 * john smith
 * jim johnson
 * sue rabon
 *
 */

在有了yield这个关键字以后,我们可以通过这样的方式来创建枚举器:

using system;
using system.collections;

// simple business object.
public class person
{
  public person(string fname, string lname)
  {
    this.firstname = fname;
    this.lastname = lname;
  }

  public string firstname;
  public string lastname;
}

// collection of person objects. this class
// implements ienumerable so that it can be used
// with foreach syntax.
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];
    }
  }

  // implementation for the getenumerator method.
  ienumerator ienumerable.getenumerator()
  {
    for (int i = 0; i < _people.length; i++)
    {
      yield return _people[i];
    }
  }

}


class app
{
  static void main()
  {
    person[] peoplearray = new person[3]
    {
      new person("john", "smith"),
      new person("jim", "johnson"),
      new person("sue", "rabon"),
    };

    people peoplelist = new people(peoplearray);
    foreach (person p in peoplelist)
      console.writeline(p.firstname + " " + p.lastname);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网