C#面试题更新 2026-08-03

在 C# 中,使用 List<T>.ForEach 方法与使用传统的 foreach 循环遍历集合时,它们在执行方式、适用场景和潜在风险上有哪些不同?请从委托调用、异常处理、修改集合、性能等方面进行对比。

考察说明

考察对 C# 集合遍历两种方式的底层机制和差异的理解。

回答思路

  1. 【回答框架 1】List<T>.ForEach 是 List<T> 类的方法,接受一个 Action<T> 委托作为参数,该方法内部通过 for 循环遍历集合并依次调用委托。传统 foreach 是语言级语法糖,编译后使用迭代器模式,通过调用 GetEnumerator 和 MoveNext 逐个访问元素。
  2. 【回答框架 2】ForEach 方法要求集合必须是非 null 的 List<T>,而 foreach 可以用于任何实现了 IEnumerable 或 IEnumerable<T> 的集合,包括数组、List、字典等。ForEach 只能操作 List<T>,而 foreach 更通用。
  3. 【回答框架 3】在修改集合元素时,ForEach 内部使用索引访问,可以在委托中修改元素的值(但修改元素属性或字段),不过不能修改集合结构(添加或删除元素),否则会导致 InvalidOperationException。foreach 在迭代期间修改集合结构也会抛出同样的异常。
  4. 【回答框架 4】ForEach 方法直接调用委托,性能上略高于 foreach 因为减少了迭代器的开销,但差异很小。在异常处理方面,ForEach 在委托中抛出的异常会终止整个遍历,而 foreach 中可以在循环体内捕获异常并继续下一次迭代,但若在循环体内未捕获,同样终止。
  5. 【回答框架 5】适用场景上,ForEach 适合对每个元素执行简单操作,能简化代码;foreach 则更灵活,支持 break、continue、return 等控制流语句,且不限于 List<T>,代码可读性高。
  6. 【关键点 1】List<T>.ForEach 是 List<T> 的实例方法,接受 Action<T> 委托,内部用 for 循环实现;foreach 是语法糖,使用迭代器。
  7. 【关键点 2】ForEach 无法使用 break 或 continue 控制流,foreach 可以。
  8. 【关键点 3】两者在迭代中修改集合结构都会抛出 InvalidOperationException,但 ForEach 不能通过修改集合长度来停止遍历,foreach 可以使用 break 避免。
  9. 【易错点 1】误以为 ForEach 和 foreach 在修改集合上的行为完全一致,实际上 ForEach 在委托中修改元素本身不会报错,但若修改集合结构则同样异常。
  10. 【易错点 2】忽略 ForEach 不能使用 await 异步委托,而 foreach 可以直接 await。