c#中容易被忽视的foreach
有句俗语:百姓日用而不知。我们c#程序员很喜欢,也非常习惯地用foreach。今天呢,我就带大家一起探索foreach,走,开始我们的旅程。
一、for语句用的好好的,为什么要提供一个foreach?
for (var i = 0; i < 10; i++)
{
//to do sth
} foreach (var n in list)
{
//to do sth
}
首先,for循环,需要知道循环的次数,foreach不需要。其次,for循环在遍历对象的时候,略显麻烦,还需要通过下标索引找到当前对象,foreach不需要这么麻烦,显得更优雅。最后,for循环需要知道集合的细节,foreach不需要知道。
这一切的好处,得益于微软的封装,那我们看看foreach生成的IL代码:
IL_00a7: callvirt instance valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<!0>
class [System.Collections]System.Collections.Generic.List`1<int64>::GetEnumerator()
.try
{
IL_00ae: br.s IL_00c9
IL_00b0: ldloca.s V_10
IL_00b2: call instance !0 valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int64>::get_Current() IL_00cb: call instance bool valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int64>::MoveNext()
IL_00d0: brtrue.s IL_00b0
IL_00d2: leave.s IL_00e3
} // end .try
finally
{
IL_00d6: constrained. valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int64>
IL_00dc: callvirt instance void [System.Runtime]System.IDisposable::Dispose()
IL_00e1: nop
IL_00e2: endfinally
} // end handlers
怎样的对象才能使用foreach呢?从微软的文档上看,实现了IEnumerable接口的对象,可以使用foreach,此接口只定义了一个方法:public System.Collections.IEnumerator GetEnumerator (); 有意思的是,它返回了一个IEnumerator接口,再看看这个接口:
有一个属性:Current和两个方法MoveNext()、Reset(),现在我们回过头来看看生成的IL代码,真相大白。foreach只不过是个好吃的语法糖而已,编译器帮我们做好了一切。和直接写foreach类似的用法还有一个,就是对象的Foreach方法:
list.ForEach(n =>
{
//to do sth
});
那问题就来了,都是foreach,我该用哪个?忍不住看看微软的源码:
internal void ForEach(Action<T> action)
{
foreach (T x in this)
{
action(x);
}
}
其实,就是定义了一个委托,我们把想要做的事情定义好,它来执行。这和直接使用foreach有何区别?我又忍不住好奇心,写了一段代码,比较了for和foreach的性能,先上结果:

说明下,最后一个是对象调用Foreach方法。数据反映的是随着数据规模下降,看运行时间有什么变化。从1亿次循环到1万次循环,耗时从几百毫秒到1毫秒以内。从图上,明显能看出性能差异,是从千万级别开始,for的性能最好,其次是对象的Foreach方法,最后是foreach。
for和foreach的性能差异,我们尚且能理解,但是对象的Foreach和直接foreach差异从何而来?我冥思苦想,百思不得其解。我试图从内存分配和垃圾回收的机制方向去理解,但是没有突破。我想着,直接foreach耗时,是不是因为,它多执行了什么东西,比如说多分配了一些变量,比如说,内存中这么大数据量,垃圾回收机制,不可能无动于衷,是不是垃圾回收机制导致的程序变慢,进而影响了性能。

我在循环完后,强行执行了一次GC,才释放了13.671875k,说明循环中,执行GC也没有什么意义,回收不了垃圾,但是如果循环中,频繁执行GC,确实会导致程序没法好好地运行。垃圾回收机制,会把不再引用的对象释放,而整个循环过程中,对象都在List中,所以GC应该不会运行。
那亲爱的程序员朋友,你觉得对象的Foreach方法和直接Foreach的性能差异,是怎么产生的呢,欢迎讨论,我把源码贴出来。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text; namespace MyConsole.Test
{
public class ForeachTest
{
public static void Test(long num)
{
Console.WriteLine("当前数据规模:" + num); DateTime start = DateTime.Now; for (var i = 0; i < num; i++)
{
var t = (i + 1) * 100 + 1;
} DateTime end = DateTime.Now; var costTime = end.Subtract(start).TotalMilliseconds; Console.WriteLine("for cost time:" + costTime + " ms"); List<long> list = new List<long>();
for (var i = 0; i < num; i++)
{
list.Add(i);
} start = DateTime.Now; foreach (var n in list)
{
var t = (n + 1) * 100 + 1;
} end = DateTime.Now; costTime = end.Subtract(start).TotalMilliseconds; Console.WriteLine("foreach cost time:" + costTime + " ms"); start = DateTime.Now; list.ForEach(n =>
{
var t = (n + 1) * 100 + 1;
}); end = DateTime.Now; costTime = end.Subtract(start).TotalMilliseconds; Console.WriteLine("obj foreach cost time:" + costTime + " ms"); Console.WriteLine("--------------------------------------------");
Console.WriteLine("");
}
}
}
放到Main方法里:
long[] nums =
{
100000000,
10000000,
1000000,
100000,
10000,
}; foreach (int num in nums)
{
for (int i = 0; i < 5; i++)
{
ForeachTest.Test(num);
}
} Console.ReadLine();
最后注意一点的是,foreach循环里面,不能随便添加或者删除元素,如果允许的话,程序将很难控制,而且非常容易出错,所以微软不允许这么干。
c#中容易被忽视的foreach的更多相关文章
- 了解PHP中的Array数组和foreach
1. 了解数组 PHP 中的数组实际上是一个有序映射.映射是一种把 values 关联到 keys 的类型.详细的解释可参见:PHP.net中的Array数组 . 2.例子:一般的数组 这里,我 ...
- Java中LinkedList的fori和foreach效率比较
在<Java中ArrayList的fori和foreach效率比较>中对ArrayList的两种循环方式进行了比较,本次对LinkedList的两种遍历方式进行效率的比较. 1. list ...
- Mybatis中的in查询和foreach标签
Mybatis中的foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separato ...
- Java中的可变参数以及foreach语句
Java中的可变参数的定义格式如下: 返回值类型 方法名称(类型 ... 参数名称){} foreach语句的格式如下: for ( 数据类型 变量名称 :数据名称){ ... } public ...
- Java中的增强 for 循环 foreach
foreach 是 Java 中的一种语法糖,几乎每一种语言都有一些这样的语法糖来方便程序员进行开发,编译期间以特定的字节码或特定的方式来对这些语法进行处理.能够提高性能,并减少代码出错的几率.在 J ...
- 空数组在以下三种遍历中均不可更改:forEach、map和for...in
首先,我们要知道对于forEach.map和for...in三种遍历,在不是空数组的情况下,要想实现更改原数组的方法,代码如下: var list = [1,2,3,4]; var list1 = [ ...
- js数组中的find(), findIndex(), filter(), forEach(), some(), every(), map(), reduce()方法的详解和应用实例
1. find()与findIndex() find()方法,用于找出第一个符合条件的数组成员.它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该 ...
- 浅谈C#中的for循环与foreach循环
for循环和foreach循环其实可以算得上是从属关系的,即foreach循环是可以转化成for循环,但是for循环不一定能转换成foreach循环. 下面简单介绍一下两种循环: 1.for循环 代码 ...
- Java中ArrayList的fori和foreach效率比较
1. list的元素为Integer [代码实例1] public static void main(String[] args) { List<Integer> list = new A ...
随机推荐
- Python制作手游《和平精英》游戏资料查询助手
写在前面的一些P话: <和平精英>这个游戏想必大家都玩过了,今天来教大家制作一个<和平精英>游戏的资料查询助手 受害者地址: https://gp.qq.com/main.sh ...
- 对象映射 - Mapping.Mapster
前言 在项目中我们会经常遇到对象的映射,比如像Model和Dto之间的映射,或者是对象的深拷贝,这些都是需要我们自己实现的.此时,项目中会出现很多初始化对象的代码,这些代码写起来相当的枯燥乏味,那么有 ...
- Multiparty Cardinality Testing for Threshold Private Set-2021:解读
本文记录阅读该论文的笔记. 本文基于阈值加法同态加密方案提出了一个新的允许\(N\)方检查其输入集的交集是否大于\(n-t\)的IPSI方案,该协议的通信复杂度为\(O(Nt^2)\). 注意:\(N ...
- 抓包整理外篇fiddler———— 会话栏与过滤器[二]
前言 简单介绍一下会话栏和过滤器 正文 在抓包的时候这两个可以说是必用吧. 会话栏: 会话栏我这里介绍根据左边部分和右边部分. 左边部分是一些图标,有些人发现有个习惯,不习惯看图标. 其实说白了,我们 ...
- 讲给测试人员的docker知识
docker对测试来说有什么用 docker类似于Windows系统的虚拟机,对于测试来说docker意味着一种新的测试环境部署方式,由于其镜像分层的设置,我们可以在一台物理机上同过docker的方式 ...
- 【cartographer_ros】五: 发布和订阅陀螺仪Imu信息
上一节介绍了里程计Odometry传感数据的订阅和发布. 本节会介绍陀螺仪Imu数据的发布和订阅.陀螺仪在cartographer中主要用于前端位置预估和后端优化. 目录 1:sensor_msgs/ ...
- Lambda表达式的无参数无返回值的练习和Lambda表达式有参数有返回值的练习
使用Lambda(无参无返回) 说明:给定一个厨师(Cook)接口,内含唯一的抽象方法makeFood,且无参数.无返回值.如下: public interface Cook{ public abst ...
- 云ATM架构设计
云ATM架构设计 启动程序(Start.java) public class Start { public static void main(String[] args) { MainView vie ...
- Data too long for column 'xxx' at row
Data too long for column 'xxx' at row 数据库的默认的utff-8,且连接的字符串也设置了utf-8,数据库字段用的text,但是还是报错,原因超出了长度,要最大的 ...
- APISpace 分钟级降水预报API接口 免费好用
各种不同类型的降水对国民经济和国防建设会产生不同的影响.无论农业生产.航空.航海.交通运输.水利建设.防涝防旱等都需要以及准确的降水预报. 分钟级降水预报API,支持国内任一经纬度的预报数据,实时 ...