1. foreach介绍
在C#中,foreach是一种循环语句,用于遍历数组、集合或字符串等容器中的元素,以便逐个处理每个元素。语法如下:
foreach (var item in collection)
{
// 执行语句
}
其中,var item 表示当前集合中的一个元素,collection 表示要遍历的容器对象。在循环语句执行过程中,每次取出一个元素并存储到 item 中,然后执行循环体中的语句。
2. foreach特点
2.1 可变性
foreach 循环的容器可以是一个变量,也可以是一个固定的值,因此可以动态地改变遍历的集合。例如:
List<int> myList = new List<int>();
// 向 myList 中添加元素
foreach (int item in myList)
{
// 执行语句
}
或者:
foreach (int item in new int[] { 1, 2, 3, 4 })
{
// 执行语句
}
2.2 安全性
使用 foreach 循环时,编译器会对容器进行越界检查,避免程序在运行时出现异常。例如:
List<int> myList = new List<int>();
// 向 myList 中添加元素
foreach (int item in myList)
{
Debug.WriteLine(item);
}
这段代码在 myList 为空时不会出现异常,因为 foreach 循环不会尝试取出不存的元素。
3. foreach实现原理
foreach 语句实际上是对 IEnumerator 接口的封装,IEnumerator 接口可以实现对集合中的元素进行迭代。foreach 循环在编译时会被编译器翻译为类似如下的代码:
IEnumerator<int> enumerator = myList.GetEnumerator(); // 获取 IEnumerator 对象
try
{
while (enumerator.MoveNext()) // 当集合中还有下一个元素时循环
{
int item = enumerator.Current; // 取出当前元素
// 执行语句
}
}
finally
{
if (enumerator is IDisposable disposable) // 处理资源释放
{
disposable.Dispose();
}
}
由此可以看出,foreach 循环的实现原理就是通过 IEnumerator 接口对集合进行遍历,而 IEnumerator 接口的实现依靠 yield return 语句,yield return 语句可以简化自定义枚举器的实现过程。例如:
public class MyList<T> : IEnumerable<T>
{
private List<T> items = new List<T>();
// 构造函数
public MyList(IEnumerable<T> collection)
{
items.AddRange(collection);
}
// 实现 GetEnumerator 方法
public IEnumerator<T> GetEnumerator()
{
foreach (T item in items)
{
yield return item;
}
}
// 显式实现 IEnumerable.GetEnumerator 方法
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
上述代码展示了如何通过 yield return 语句实现自定义 MyList 枚举器,并作为 IEnumerable<T> 的成员返回。使用 foreach 循环遍历 MyList 时,就是通过枚举器来进行元素的遍历。
4. foreach与性能
foreach 语句的使用会带来一定的性能损失,因为其在每次遍历元素时需要执行额外的代码。为了比较 foreach 循环与 for 循环的性能,下面分别给出两者的代码:
List<int> myList = new List<int>();
// 向 myList 中添加元素
foreach (int item in myList)
{
Debug.WriteLine(item);
}
和
List<int> myList = new List<int>();
// 向 myList 中添加元素
for (int i = 0; i < myList.Count; i++)
{
Debug.WriteLine(myList[i]);
}
使用 Stopwatch 对两种代码进行计时,得到的结果如下:
// foreach 循环消耗时间:10.4326 ms
Stopwatch sw = new Stopwatch();
sw.Start();
foreach (int item in myList)
{
}
sw.Stop();
Debug.WriteLine($"foreach 循环消耗时间:{sw.Elapsed.TotalMilliseconds} ms");
// for 循环消耗时间:3.202 ms
sw.Restart();
for (int i = 0; i < myList.Count; i++)
{
}
sw.Stop();
Debug.WriteLine($"for 循环消耗时间:{sw.Elapsed.TotalMilliseconds} ms");
由上述结果可以看出,for 循环比 foreach 循环的执行速度要快得多,因此在对性能要求较高的场景下,应尽可能采用 for 循环实现循环。
总结
本文从 foreach 的介绍开始,逐步详解了其特点、原理及性能,并给出了代码示例。通过阅读本文,读者可以更深入地了解 C# 中的 foreach 循环,并在实际编程过程中充分发挥其优点,使代码更加简洁高效。