我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何在C#中使用foreach语句

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何在C#中使用foreach语句

今天就跟大家聊聊有关如何在C#中使用foreach语句,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

C# foreach语句不仅仅只是do...while或者for循环语句的一个变体。它会为我们的集合产生***的遍历代码。实际上,foreach语句的定义和.NET框架中的集合接口密切相关。对于一些特殊的集合类型,C#编译器会产生具有***效率的代码。遍历集合时,我们应该使用C# foreach语句,而非其他的循环构造。例如,对于下面三种循环:

int [] foo = new int[100];   // 循环1:   foreach ( int i in foo)   Console.WriteLine( i.ToString( ));   // 循环2:   for ( int index = 0;   index < foo.Length;   index++ )   Console.WriteLine( foo[index].ToString( ));   // 循环3:   int len = foo.Length;   for ( int index = 0;   index < len;   index++ )   Console.WriteLine( foo[index].ToString( ));

对于当前和将来的C#编译器(版本1.1及其以上版本),第1个循环产生的代码***,而且需要键入的字符也最少,因此程序员的开发效率也比较高。(不过在C# 1.0编译器下,第1个循环产生的代码效率较慢,第2个循环产生的代码效率***。)大多数C和C++程序员认为效率***的第3循环,反而是最坏的选择。通过将Length变量放到循环之外,我们实际上阻碍了JIT编译器移除循环中的范围检查。

C#代码运行在一个安全、托管的环境中。每一个内存位置都会被检查,包括数组索引。事实上,第3个循环所产生的代码和如下的代码等效:

// 循环3, 和编译器产生的代码等效:   int len = foo.Length;   for ( int index = 0;   index < len;   index++ )   {   if ( index < foo.Length )   Console.WriteLine( foo[index].ToString( ));   else  throw new IndexOutOfRangeException( );   }

JIT和C#编译器并不“喜欢”我们用这种方式来帮助它们。将Length属性放到循环之外只会让JIT编译器做更多的工作,产生的代码也更慢。CLR会确保我们写的代码不会滥用变量拥有的内存。CLR会在访问每一个特定数组元素之前,产生一个数组界限(并非上面的len变量)测试。如果我们像上面那样写代码,每一个数组界限测试会被执行两次。

在循环的每一次迭代中,我们都要对数组索引做两次检查。第1个循环和第2个循环更快的理由在于C#编译器和JIT编译器可以确保循环中的数组界限是安全的。只要循环变量不是数组的Length属性,每一次迭代时都会执行数组界限检查。

对于1.0版本的C#编译器,在数组上使用foreach语句产生的代码比较慢的原因在于装箱操作(有关装箱的详细讨论,参见条款17)。在.NET中,数组是类型安全的。1.1版本之后的C#编译器会为数组与其他集合产生不同的IL。在1.0版本的编译器产生的代码中,在数组上使用foreach语句实际上是通过IEnumerator接口来遍历数组,而这会导致装箱与拆箱操作:

IEnumerator it = foo.GetEnumerator( );   while( it.MoveNext( ))   {   int i = (int) it.Current; // 这里将出现装箱和拆箱。   Console.WriteLine( i.ToString( ) );   }

相反,对于1.1版本之后的C#编译器,在数组上使用foreach语句将产生类似如下的构造:

for ( int index = 0;   index < foo.Length;   index++ )   Console.WriteLine( foo[index].ToString( ));

由于foreach语句总会产生***的代码,所以我们不必刻意去记忆哪种构造会产生***效的循环构造——foreach和编译器会为我们做这些工作。

如果效率还不能说服大家,那么来看看语言互操作的情况。总有一些人(其中的大多数人都有使用其他一些编程语言的经验)坚定地认为数组的起始索引变量应该从1(而非0)开始。不管我们怎么费力地说服他们,都无法改变他们的这个习惯。.NET开发组在这个问题上已经尽力了。我们可以在C#语言中用如下的初始化方式,来获得一个起始索引不为0的数组:

// 创建一个一维数组,范围为 [ 1 .. 5 ]。   Array test = Array.CreateInstance( typeof( int ),   new int[ ]{ 5 }, new int[ ]{ 1 });

很多人面对这样的代码可能会退缩,转而使用起始索引为0的数组。但是总有一些人对此比较顽固。不管你怎么努力,这些人都会坚持从1开始索引数组。幸运地是,在这个问题上我们可以使用foreach语句来蒙混编译器:

foreach( int j in test )   Console.WriteLine ( j );

这里的foreach语句知道如何获得数组的上下界,因此就不必烦劳我们——而且其效率和我们手写的for循环一样快,不管其他人采用的数组下界是多少,我们使用这种做法都可以正常工作。

另外,C# foreach语句还可以为我们带来其他好处。其中的循环变量是只读的——也就是说我们不能替换foreach语句中的集合对象。而且还存在一个显式强制转型。如果集合中保存的对象类型不正确,迭代语句将抛出一个异常。

对于多维数组,foreach语句也有类似的好处。假设我们要创建一个棋盘,我们可能会编写如下的两段代码:

private Square[,] _theBoard = new Square[ 8, 8 ];   // 另外地方的代码:   for ( int i = 0; i < _theBoard.GetLength( 0 ); i++ )   for( int j = 0; j < _theBoard.GetLength( 1 ); j++ )   _theBoard[ i, j ].PaintSquare( );

使用foreach语句,我们可以将上面的遍历代码做如下的简化:

foreach( Square sq in _theBoard )   sq.PaintSquare( );

不管数组的维数是多少,foreach语句都会产生正确的遍历代码。如果我们之后又要做一个3D棋盘,上面的foreach循环仍然会正常工作。而其他手写的循环代码就需要更改了:

for ( int i = 0; i < _theBoard.GetLength( 0 ); i++ )   for( int j = 0; j < _theBoard.GetLength( 1 ); j++ )   for( int k = 0; k < _theBoard.GetLength( 2 ); k++ )   _theBoard[ i, j, k ].PaintSquare( );

事实上,对于在每一维上拥有不同下界的多维数组来讲,foreach循环也会正常工作。这里我就不再编写这样的示例代码了。如果有人使用那样的集合,我们要知道foreach语句也能处理它。

如果我们刚开始使用的是数组,后来又需要转向其他数据结构,foreach语句允许我们不用更改绝大多数代码,从而保持代码的灵活性。假设我们刚开始有如下一个简单的数组:

int [] foo = new int[100];

但过了一段时间后,我们发现该数组无法方便地处理我们需要的某种功能。这时候,我们选择将数组更改为ArrayList:

// 设置初始大小:   ArrayList foo = new ArrayList( 100 );

这样更改之后,任何手写的for循环代码都将遭到破坏:

int sum = 0;   for ( int index = 0;   // 下面的代码将不能编译:ArrayList 使用Count,而非Length。   index < foo.Length;   index++ )   //下面的代码将不能编译:foo[ index ] 是一个object,而非int。   sum += foo[ index ];

而使用foreach语句,它会编译为不同的代码,自动将每一个操作数强制转换为正确的类型。我们在代码上无需做任何更改。事实上,使用foreach语句不仅可以更改为标准集合类型——任何集合类型都可以使用foreach。

如果我们支持.NET环境为集合所定义的规则,用户便可以使用foreach来遍历我们的类型成员。要让foreach语句将一个类看做集合类型,该类必须拥有一些属性。总共有3种方式可以使一个类成为集合类:类型具备一个公有的GetEnumerator()方法;类型显式实现了IEnumerable接口;类型实现了IEnumerator接口。

***,C# foreach语句还会为我们在资源管理方面带来额外的好处。IEnumerable接口只包含一个方法:GetEnumerator()。在一个支持IEnumerable接口的类型上使用foreach语句会产生类似如下的代码(会有一些优化):

IEnumerator it = foo.GetEnumerator( ) as IEnumerator;   using ( IDisposable disp = it as IDisposable )   {   while ( it.MoveNext( ))   {   int elem = ( int ) it.Current;   sum += elem;   }   }

如果编译器可以确定类型对IDisposable接口的实现情况,那么它就会自动优化finally块中的语句。

综上所述,foreach是一个非常有用的语句。它会使用***效的构造为“数组的上下界索引”、“多维数组遍历”和“操作数转型”产生正确的代码,并且产生的是***效率的循环结构。它是遍历集合的***方式。使用它,我们编写的代码将比较“经久耐用”,而且在刚开始编写的时候也比较简单。使用foreach为我们带来的开发效率提升可能很少,但是随着时间的推移,它的效益会不断增长。

看完上述内容,你们对如何在C#中使用foreach语句有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网行业资讯频道,感谢大家的支持。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何在C#中使用foreach语句

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何在C#中使用foreach语句

今天就跟大家聊聊有关如何在C#中使用foreach语句,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。C# foreach语句不仅仅只是do...while或者for循环语句的一个变体
2023-06-17

C#中如何使用foreach语句

C#中如何使用foreach语句,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C# foreach语句示例说明:要对集合中的内容进行增删改的操作,那么就是要遍历集合,那么C
2023-06-17

Linq中如何使用foreach语句

这篇文章给大家介绍Linq中如何使用foreach语句,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Linq 有很多值得学习的地方,这里我们主要介绍Linq foreach语句,包括介绍foreach循环来强制执行查询
2023-06-17

C#中foreach语句怎么用

小编给大家分享一下C#中foreach语句怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!C# foreach语句是在C#中新引入的,在C和C++中没有这个语
2023-06-17

C#中foreach如何使用

本篇文章给大家分享的是有关C#中foreach如何使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C# foreach使用1. MySplit 类///
2023-06-17

如何在C语言中使用break和continue语句

如何在C语言中素break和continue语句?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。for循环中break和continue语句的用法输出100~ 2
2023-06-14

C#中如何使用Switch语句

这期内容当中小编将会给大家带来有关C#中如何使用Switch语句,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。C# Switch语句这个语句求一个表达式的值,并将这个值与许多case进行比较。每个case
2023-06-18

如何在Nodejs中使用forEach

如何在Nodejs中使用forEach?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。利用数组对象方法push/shift可实现队列先进先出特性,例如:>a=[][]>a.pus
2023-06-06

如何在PHP中使用foreach

今天就跟大家聊聊有关如何在PHP中使用foreach,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。语言基础foreach 语法结构提供了遍历数组的简单方式。php5之前, forea
2023-06-15

c语言中default语句如何使用

在C语言中,default语句用于switch语句中的默认情况。当没有任何一个case匹配时,会执行default语句块中的代码。使用default语句的一般语法如下:switch (expression) {case value1:/
c语言中default语句如何使用
2023-10-28

C++中如何使用switch-case语句

今天就跟大家聊聊有关C++中如何使用switch-case语句,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。if语句处理两个分支,处理多个分支时需使用if-else-if结构,但如果
2023-06-17

C语言中如何使用do-while语句

这篇文章给大家介绍C语言中如何使用do-while语句,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。while循环和for循环都是入口条件循环,即在循环的每次迭代之前检查测试条件,所以有可能根本不执行循环体中的内容。C
2023-06-16

return语句如何在python中使用

return语句如何在python中使用?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统
2023-06-14

如何在python中使用raise语句

这期内容当中小编将会给大家带来有关如何在python中使用raise语句,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。python主要应用领域有哪些1、云计算,典型应用OpenStack。2、WEB前端开
2023-06-14

如何在Shell中使用eval语句

如何在Shell中使用eval语句?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。功能说明:告知shell取出eval的参数,重新运算求出参数的内容。语  法:e
2023-06-09

如何在java中使用while语句

本篇文章给大家分享的是有关如何在java中使用while语句,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各
2023-06-14

如何在python中使用finally语句

这篇文章给大家介绍如何在python中使用finally语句,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,Python对代码格式的要求
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录