- 背景知识
- for 循环重复执行一个语句或语句块,直到指定的表达式计算为 false 值。for 循环对于迭代数组和顺序处理非常方便。
foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用;
迭代器是 C# 2.0 中的新功能。迭代器是方法、get 访问器或运算符,它使您能够在类或结构中支持 foreach 迭代,而不必实现整个 IEnumerable 接口 具体参考:MSDN
- for VS foreach
- for和foreach都可以对集合和数组的元素进行逐个处理。 关于for和foreach有什么区别那?主要从以下方面进行比较
- 语法方面
- 语义方面
- 性能方面
- 线程安全
- 使用foreache的一点体会
- 语法方面
-
- 简洁,方面
forforeach, c.Weight);
}List<Car> carlist = new List<Car>();可以看出,对于集合的遍历, foreach比for简洁。当然,如果只遍历集合的一部分,foreach爱莫能助了。
foreach (Car c in carlist)
{
Console.Write("{0}", c.Weight);
}
- 迭代变量的读写性方面 对于for,迭代变量是可读可写的,foreach是只读的。为什么?
能使用foreach的集合必须实现IEnumerable接口。Reflector IEnumerable的IL代码如下:
[ComVisible(true), Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
在接着看 System.Collections.IEnumerator GetEnumerator() 里面的:
[ComVisible(true), Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerator
{
bool MoveNext();
object Current { get; }
void Reset();
}
注意:
object Current { get; }
是不是很熟悉,只读属性,就解释了为什么foreach迭代变量为只读的了。
- 简洁,方面
- 语义方面
- 学习开发语言,我觉得语义比语法更重要.学习英语我觉得也是如此。
foreach 传达出来的语义就是对于集合一个一个检索,而for就是一循环结构。
个人觉得foreach 可以嗅出面向对象的味道来。
- 性能方面
- 关于性能方面我不能多说什么,你可以自己动手测试。下面是我的一段测试代码,供参考,如果你有更好的性能代码测试,可以写出来.究竟如何选择,参见:《Effective C#》 - 条款11:优先采用foreach循环语句
sub;
}
}
C#的foreach语句不仅仅只是do... while或者for循环语句的一个变体。它会为我们的集合产生最好的遍历代码。实际上,foreach语句的定义和.NET框架中的集合接口密切相关。 对于一些特殊的集合类型,C#编译器会产生具有最佳效率的代码。遍历集合时,我们应该使用foreach语句,而非其他的循环构造
- 线程安全
- 对于一个集合,在遍历过程中,如果集合发生异动,foreach会发生异常,而for不会。
这个是一个曾经电话面试过我的一个工程师说的,我觉得这句话值得商榷,只是在.Net Framework提供的常见集合(Array,List等)会发生,发生异常代码参考: -
这个异常原因可以参见: 在Dictionary使用foreach的注意 如果你自己动手实现迭代器就不会了。代码如下:
);
}
} -
对于一个集合,在遍历过程中,如果集合发生异动,foreach会发生异常,而for不会,foreach本身没有错,关键看你如何实现迭代器。
value;
}
}
}
- 使用foreache的一点体会
-
- 使用lock 对于你能掌控的代码,把这个集合变量作为一个临界变量,使用lock加锁,确保代码不会出现“集合已修改;可能无法执行枚举操作。”类似异常。如下代码供参考:
注意lock用法。
);
}
}
}
- 使用本地变量拷贝 把这个集合变量拷贝到本地变量,然后对本地变量进行遍历。
;
}
- 使用lock 对于你能掌控的代码,把这个集合变量作为一个临界变量,使用lock加锁,确保代码不会出现“集合已修改;可能无法执行枚举操作。”类似异常。如下代码供参考: