首页 后端开发 C#.Net教程 C#中关于foreach实现的原理详解

C#中关于foreach实现的原理详解

Oct 05, 2017 pm 03:32 PM
.net foreach

这篇文章主要为大家详细介绍了C#中foreach实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文主要记录我在学习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类型,这就涉及到可枚举类型和枚举器的概念。

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


// 摘要:
//   公开枚举器,该枚举器支持在非泛型集合上进行简单迭代。
  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();
  }
登录后复制

以下是自定义一个迭代器的示例(https://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx):


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);
  }
}
登录后复制

以上是C#中关于foreach实现的原理详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java ArrayList遍历时使用foreach和iterator删除元素的区别是什么? Java ArrayList遍历时使用foreach和iterator删除元素的区别是什么? Apr 27, 2023 pm 03:40 PM

一、Iterator和foreach的区别多态差别(foreach底层就是Iterator)Iterator是一个接口类型,他不关心集合或者数组的类型;for和foreach都需要先知道集合的类型,甚至是集合内元素的类型;1.为啥说foreach底层就是Iterator编写的代码:反编译代码:二、foreach与iterator时remove的区别先来看阿里java开发手册但1的时候不会报错,2的时候就会报错(java.util.ConcurrentModificationException)首

php如何判断foreach循环到第几个 php如何判断foreach循环到第几个 Jul 10, 2023 pm 02:18 PM

​php判断foreach循环到第几个的步骤:1、创建一个“$fruits”的数组;2、创建一个计数器变量“$counter”初始值为0;3、使用“foreach”循环遍历数组,并在循环体中增加计数器变量的值,再输出每个元素和它们的索引;4、在“foreach”循环体外输出计数器变量的值,以确认循环到了第几个元素。

C#的就业前景如何 C#的就业前景如何 Oct 19, 2023 am 11:02 AM

无论您是初学者还是有经验的专业人士,掌握C#将为您的职业发展铺平道路。

分享几个.NET开源的AI和LLM相关项目框架 分享几个.NET开源的AI和LLM相关项目框架 May 06, 2024 pm 04:43 PM

当今人工智能(AI)技术的发展如火如荼,它们在各个领域都展现出了巨大的潜力和影响力。今天大姚给大家分享4个.NET开源的AI模型LLM相关的项目框架,希望能为大家提供一些参考。https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一种开源的软件开发工具包(SDK),旨在将大型语言模型(LLM)如OpenAI、Azure

PHP返回一个键值翻转后的数组 PHP返回一个键值翻转后的数组 Mar 21, 2024 pm 02:10 PM

这篇文章将为大家详细讲解有关PHP返回一个键值翻转后的数组,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。PHP键值翻转数组键值翻转是一种对数组进行的操作,它将数组中的键和值进行交换,生成一个新的数组,其中原始键作为值,原始值作为键。实现方法在php中,可以通过以下方法对数组进行键值翻转:array_flip()函数:array_flip()函数专门用于键值翻转操作。它接收一个数组作为参数,并返回一个新的数组,其中键和值已交换。$original_array=[

PHP返回数组中的当前元素 PHP返回数组中的当前元素 Mar 21, 2024 pm 12:36 PM

这篇文章将为大家详细讲解有关PHP返回数组中的当前元素,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。获取PHP数组中的当前元素php为访问和操作数组提供了多种方法,其中包括获取数组中的当前元素。以下介绍几种常用的技术:1.current()函数current()函数返回数组内部指针当前指向的元素。指针最初指向数组的第一个元素。使用以下语法:$currentElement=current($array);2.key()函数key()函数返回数组内部指针当前指向元

foreach和for循环的区别是什么 foreach和for循环的区别是什么 Jan 05, 2023 pm 04:26 PM

区别:1、for通过索引来循环遍历每一个数据元素,而forEach通过JS底层程序来循环遍历数组的数据元素;2、for可以通过break关键词来终止循环的执行,而forEach不可以;3、for可以通过控制循环变量的数值来控制循环的执行,而forEach不行;4、for在循环外可以调用循环变量,而forEach在循环外不能调用循环变量;5、for的执行效率要高于forEach。

面向开发人员的.NET性能优化技术 面向开发人员的.NET性能优化技术 Sep 12, 2023 am 10:43 AM

如果你是一名.NET开发者,你必须意识到在交付高质量软件方面,优化功能和性能的重要性。通过熟练使用提供的资源并减少网站加载时间,你不仅为用户创造了愉快的体验,还能减少基础设施成本。

See all articles