c#中使用foreach是非常方便的操作,foreach的执行效率比for高,foreach可以在不用知道长度的情况下进行遍历,但是for一般要知道长度才能遍历,否则要在循环的内部进行控制。 foreach在c#中一般用于操作集合对象。但我在用foreach循环删除元素时遇到了麻烦,比如这样的代码:
foreach (Class.Rectangle rec in rectangles)
{
if (this.searchedlayer.Equals(rec.Outlayer) && rec.Number == 3)
{
this.selectedrectangle = rec;
this.rectangles.Remove(this.selectedrectangle);
}
}
这样写的话运行会出错:集合已修改,可能无法执行枚举操作 foreach。
因为foreach是取只读的,在取的时候数据不能变(包括修改,删除,添加等),当修改了集合的元素时,地址可能发生某种改变,所以不跳出循环继续遍历时,就可能出现引用找不到的情况。所以要把代码改成这样:
foreach (Class.Rectangle rec in rectangles)
{
if (this.searchedlayer.Equals(rec.Outlayer) && rec.Number == 3)
{
this.selectedrectangle = rec;
break;
}
}
this.rectangles.Remove(this.selectedrectangle);
如果要循环删除可以增加一个for循环:
for (int i = 0; i < rectangles.Count; i++)
{
foreach (Class.Rectangle rec in rectangles)
{
if (this.searchedlayer.Equals(rec.Outlayer) && rec.Number == 3)
{
this.selectedrectangle = rec;
break;
}
}
this.rectangles.Remove(this.selectedrectangle);
}
只读的原因:
namespace System.Collections { // 摘要: // 支持对非泛型集合的简单迭代。 [ComVisible(true)] [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerator { // 摘要: // 获取集合中的当前元素。 // // 返回结果: // 集合中的当前元素。 // // 异常: // System.InvalidOperationException: // 枚举数定位在该集合的第一个元素之前或最后一个元素之后。 object Current { get; } bool MoveNext(); void Reset(); } } namespace System.Collections { // 摘要: // 公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。 [ComVisible(true)] [Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerable { // 摘要: // 返回一个循环访问集合的枚举数。 // // 返回结果: // 可用于循环访问集合的 System.Collections.IEnumerator 对象。 [DispId(-4)] IEnumerator GetEnumerator(); } }
每个实现的迭代器,返回类型必须为 IEnumerable、IEnumerator、IEnumerable<T> 或 IEnumerator<T>。foreach中的迭代变量是即为IEnumerable、IEnumerator、IEnumerable<T> 或 IEnumerator<T>类型。从上面的接口可以看出,object Current是只读的,因此,foreach迭代变量只能是只读的。
另:
foreach中的迭代变量本来就是只读,不可修改的。
对值类型中的属性赋值,会改变值类型对象在栈上的内存分步,所以实际上就是对值类型对象本身重新赋值了