三九宝宝网宝宝百科宝宝知识

C语言基础C#之11:PreferforeachLoops

11月11日 编辑 39baobao.com

[防缺维生素c的妙计]1、母乳中含维生素c较多,可以满足宝贝身体的需要,吃母乳的宝贝一般不容易缺乏维生素c,所以一定要坚持喂母乳。 2、哺乳妈咪多吃富含维生素c的蔬菜、水果,就可给宝贝补充丰富的维...+阅读

C&emsp的foreach表达式不仅仅是do、while、for循环的变体。它为你拥有的任何集合生成的迭代代码。它的定义和.框架中的集合接口相绑定,C&emsp编译器为这个特定类型的集合生成的代码。当你迭代集合的时候,使用foreach代替其它循环结构。看这些循环:

int[] foo = new int[100];

Loop 1:

foreach (int i in foo)

Console.WriteLine(i.ToString());

Loop 2:

for (int index = 0;index< foo.Length;index++)

Console.WriteLine(foo[index].ToString());

Loop 3:

int len = foo.Length;

for (int index = 0;index< len;index++)

Console.WriteLine(foo[index].ToString());

对于当前的和未来的c&emsp编译器(版本1.1或者更高),Loop 1是的,它甚至是打字最少的,你个人的生产力能够提高。(C&emsp1.0的编译器为Loop1生成比较慢的代码,因此在那个版本里面Loop2是的)。Loop 3 ,这个多数C和C++程序员会认为效的结构,是最坏的选择。通过将长度变量提升到循环之外,你做了如下的改变:妨碍了JIT编译器移除在循环内部检测范围的机会。

C&emsp代码运行在安全的、托管环境上。每次内存分配都被检查,包括数组的索引。通过使用一些库,Loop 3实际的代码有点像下面这样:

Loop 3, as generated by piler:

int len = foo.Length;

for (int index = 0;index< len;index++)

{

if (index< foo.Length)

Console.WriteLine(foo[index].ToString());

else

throw new IndexOutOfRangeException();

}

JITC&emsp编译器就是不喜欢你试图这样帮助它。你将对长度这个属性的访问提升到循环外部来的尝试,只会使JIT编译器做更多的工作甚至生成更慢的代码。CLR的一个保障就是你不能编写超出你的变量所拥有的内存的代码。运行时在访问每个特定的数组元素之前,会为实际的数组边界生成一个测试(不是你的len变量)。你以2遍的代价得到了一次边界的检测。

Examda提示: 需要在循环的每次重复时,为数组的索引检查付出代价,并且做了2次。Loop 1 和Loop 2更快的原因是C&emsp编译器和JIT编译器能够验证循环的边界,保证安全。任何时候,当循环变量不是数组长度时,边界检查会在每次重复时执行。

在原来的C&emsp编译器下,foreach和数组生成非常慢代码的原因在于装箱,这会在Item 17中覆盖。数组是类型安全的。现在foreach为数组生成了与其他集合不同的IL。数组的版本没有使用IEnumerator接口,该接口要求装箱和拆箱操作:

IEnumerator it = foo.GetEnumerator();

while (it.MoveNext())

{

int i = (int)it.Current; box and unbox here.

Console.WriteLine(i.ToString());

}

相反,foreach表达式为数组生成了这样的结构:

for (int index = 0;index< foo.Length;index++)

Console.WriteLine(foo[index].ToString());

foreach总是生成的代码。你没必要去记住哪个构造生成了效的循环结构:foreach和编译器会为你做这个工作。

如果效率对你来说还不够的话,那么考虑语言的互操作性。这个世界上的一些家伙(是的,他们中的多数使用其他的编程语言)强烈的相信索引变量以1开始,而不是0.无论我们如何努力,都不能打破他们的这个习惯。.小组就曾经尝试过。你不得不在C&emsp中写下这样的初始化,以便获得一个以其他非0开始的数组。

Create a single dimension array.

Its range is [ 1 .. 5 ]

Array test = Array.CreateInstance(typeof(int), new int[] { 5 }, new int[] { 1 });

这个代码足以使任何人畏缩从而仅仅编写以0开始的数组了。但是有的人非常顽固。尽你所能的努力,他们还会从1开始数。幸运的是,这是你可以强加给编译器的很多问题之一。使用foreach来迭代test数组:

foreach (int j in test)

Console.WriteLine(j);

Foreach表达式知道如何来检查数组的上限和下限,因此你没必要——同时这也和手工编码一样快,而不用管一些人决定用什么不同的下限。

foreach为你加入了其他语言的好处。循环变量是只读的:使用foreach时,你不能替换一个集合中的对象。同时,具有向正确类型的直接转换。如果集合中包含有错误类型的对象,迭代就会抛出异常。

Examda提示: foreach对于多维数组也提供了相似的好处。假设你正在创建一个棋盘。你可能写下这样的2个片段:

private Square[,] theBoard = new Square[ 8, 8 ];

elsewhere in code:

for ( int i = 0; i< theBoard.GetLength(0); i++ )

for( int j = 0; j< theBoard.GetLength(1); j++ )

theBoard[ i, j ].PaintSquare( );

相反,你可以这样来简化绘制棋盘:

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:

Set the initial size:

ArrayList foo = new ArrayList( 100 );

同时,任何对于循环的手工编码都会被破坏:

int sum = 0;

won't pile: ArrayList uses Count, not Length

for (int index = 0;index< foo.Length;index++)

won't pile: foo[ index ] is object, not int.

sum += foo[index];

然而,foreach循环编译成不同的代码:它自动将每个操作数转换成适合的类型。不需要你做任何转换。转换不仅仅是为了对集合类进行标准化,或者是为了任何集合类型都可以与foreach一起使用。

如果你支持.环境下对集合的规则,你的类型的用户可以使用foreach来对所有的成员进行迭代。对于foreach表达式,将它考虑成一个集合类型,一个必须拥有至少一个属性的类。公公的GetEnumerator()方法的存在形成了一个集合类。直接实现IEnumerable接口创建一个集合类型。实现IEnumerator接口创建一个集合类型。Foreach和它们中的任何一个都可以一起使用。

foreach有一个附加的好处,就是忽略了资源管理。IEnumerable接口包含了一个方法:GetEnumerator()。用在一个enumerable 类型上的foreach表达式生成下列的代码,同时,它进行了一些优化:

IEnumerator it = foo.GetEnumerator() as IEnumerator;

using (IDisposable disp = it as IDisposable)

{

while (it.MoveNext())

{

int elem = (int)it.Current;

sum += elem;

}

}

如果编译器能判定这个enumerator是否实现了IDisposable,它自动优化处于最终括号中的代码。但是对于你来说,看到这一点非常重要,无论怎么回事,foreach都生成正确的代码。

foreach是一个很通用的表达式。它为数组的上限和下限生成正确的代码,对多维数组进行迭代,将操作数强制转换成正确的类型(使用最有效的构造),而且,最主要的是,生成效的循环结构。它是对集合进行迭代的方法。有了它,你可以创建更持久的代码,在首先出现的地方进行编写也是容易的。使用它,是一个小小的生产力的提升,但是随着时间的变化,它的效果会增加的。

以下为关联文档:

晨尿结果出来了,CMVPCR还吗尊敬的大夫您好:前段时间我检查出的IGM(CMV)++医生吩咐我今天做晨尿检查。今天去做了晨尿检查。结果是HCMV-DNA 人体巨细胞病毒 试剂盒检测下限5.0*10^2拷贝、ML大夫说无大碍...

宝贝进入ICU保持冷静是关键把新生儿早日带回家是每个父母都期待已久的事,但如果发生了难以想象的事,比如新生儿被纳入特殊照顾一行进入到ICU病房,便会让很多父母感到害怕。任何一个父母都无法预料自己的...

TORCH有问题孩子还能要么我已经怀孕16周了,去医院做TORCH检查的时候,发现其中一项CMV为阳性,经复查后还是阳性。不知道这个孩子还能要不,也不知道这个项目对孩子以后的影响是什么,会造成什么不良反应或者...

弓形体IgG阳性IgM阴性CAg阴性我妹怀孕7个多月了,家里养了猫,虽然尽量不接触,可她的检查结果是弓形体IgG阳性IgM阴性CAg阴性,这对宝宝有没有影响?很担心啊!请帮助解答一下!谢谢! 如果是这样的话, 要去省市级以上...

bread sausage milk coffeeTeaching aims: 1 ew word :bread ausage milk coffee 2 Revisio :little car,milk 3 What day i today ? How are you ? How old are you ? Teaching aids: icture ag reor...

ABC计划南京市游府西街小学 六(2)班 蔡文睿 男孩子向妈妈说爱,就那么难?我要尝试突破。晚上七点钟,我终于制定好了A计划,备用B计划和C计划。 行动开始。 A计划为直接大声表达。我大模大样...

Playway to English—— Merry Christmas 1背景介绍p297:英国的圣诞习俗 活动目标: 1, 在圣诞环境中使孩子感知英国圣诞的习俗。 2, 在活动中,引起孩子对于不同文化和生活方式的兴趣。 活动准备: 1,请家长协助孩子利用媒体...

33周+3天BC,请看是否偏小呢双顶径82mm,股骨长60mm;胎盘前壁,成熟度2级;臀位。请问:1)宝宝偏小吗,小多少呢? 2)胎盘成熟度高吗,是不是有早产的危险呢? 3)臀位宝宝可以自己转正吗? 你的宝宝各项都是在正常范围内,不会...

我爱英语,我爱Courage我爱英语,我爱Courage! 济南市经五路幼儿园与外教课堂互动 今天早上,大一班的孩子们显得比往常活跃兴奋了许多,原来,他们的老朋友Courage要来到班里了!孩子们都焦急的等待着,热...

推荐阅读
图文推荐