C# for/foreach 循环(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在编程的世界中,循环是解决问题的核心工具之一。无论是遍历数据、重复执行任务,还是构建复杂算法,循环都能帮助开发者高效地完成工作。在 C# 中,for
和 foreach
循环是最常用的两种循环结构。对于编程初学者而言,理解它们的语法、差异和使用场景至关重要;而中级开发者则可以通过深入学习它们的高级技巧,进一步提升代码的简洁性和性能。本文将从基础到进阶,结合实际案例,系统讲解 C# for/foreach 循环的用法与最佳实践。
基础语法:for 循环
1. 核心结构与执行逻辑
for
循环适用于已知循环次数的场景。其语法结构如下:
for (初始化表达式; 条件判断; 迭代表达式)
{
// 循环体
}
- 初始化表达式:通常用于定义循环变量(如
int i = 0
)。 - 条件判断:每次循环前判断是否满足条件,若为
false
,循环终止。 - 迭代表达式:在每次循环结束后更新循环变量(如
i++
)。
示例:遍历 0 到 4 的整数:
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
// 输出:0 1 2 3 4
2. 形象比喻:像按计划旅行
可以将 for
循环想象为一次有明确路线的旅行:
- 初始化表达式 = 出发前准备行李;
- 条件判断 = 检查是否到达终点;
- 迭代表达式 = 每天前进固定距离。
foreach 循环:专为集合设计
1. 核心语法与适用场景
foreach
循环专门用于遍历 集合或数组,其语法简洁直观:
foreach (var element in collection)
{
// 处理 element
}
- element:每次循环中代表集合中的一个元素。
- collection:需要遍历的数组或实现了
IEnumerable
接口的集合(如List<T>
)。
示例:遍历字符串数组:
string[] fruits = { "Apple", "Banana", "Cherry" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
// 输出:Apple Banana Cherry
2. 形象比喻:跟着导游的旅行
foreach
循环就像跟随导游游览景点:
- 导游(集合):负责管理路线和元素顺序;
- 游客(循环代码):只需关注当前景点(元素),无需关心如何移动到下一个位置。
for 与 foreach 的核心差异
对比维度 | for 循环 | foreach 循环 |
---|---|---|
适用场景 | 已知循环次数或需要精确控制索引 | 遍历集合或数组,无需索引 |
索引控制 | 可直接访问索引(如 array[i] ) | 无法直接获取索引,需通过额外变量实现 |
修改集合 | 可能引发异常(如修改集合的大小) | 直接修改集合会抛出 InvalidOperationException |
代码简洁性 | 需手动管理变量,代码略显冗长 | 语法简洁,适合快速遍历 |
进阶用法与技巧
1. 嵌套循环:构建多维结构
嵌套循环可以处理矩阵、表格等多维数据。例如,遍历一个二维数组:
int[,] matrix = {
{ 1, 2 },
{ 3, 4 },
{ 5, 6 }
};
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
Console.Write(matrix[i, j] + " ");
}
Console.WriteLine();
}
// 输出:1 2
// 3 4
// 5 6
2. 提前终止循环:break 与 continue
break
:立即跳出整个循环;continue
:跳过当前迭代,进入下一次循环。
// 使用 break 示例
for (int i = 0; i < 10; i++)
{
if (i == 5) break;
Console.Write(i + " ");
}
// 输出:0 1 2 3 4
3. foreach 的局限性与解决方案
如果需要在 foreach
中获取元素的索引,可以通过以下方式实现:
string[] colors = { "Red", "Green", "Blue" };
for (int index = 0; index < colors.Length; index++)
{
Console.WriteLine($"索引 {index}: {colors[index]}");
}
// 或者使用 LINQ 的 Select 方法:
foreach (var pair in colors.Select((value, index) => new { value, index }))
{
Console.WriteLine($"索引 {pair.index}: {pair.value}");
}
实际案例与性能对比
1. 案例 1:计算斐波那契数列
// 使用 for 循环计算前 10 项斐波那契数列
int n = 10;
int[] fibonacci = new int[n];
fibonacci[0] = 0;
fibonacci[1] = 1;
for (int i = 2; i < n; i++)
{
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
}
foreach (int num in fibonacci)
{
Console.Write(num + " ");
}
// 输出:0 1 1 2 3 5 8 13 21 34
2. 案例 2:处理订单数据
假设有一个订单列表,需要筛选出总价超过 1000 元的订单:
List<Order> orders = GetOrders();
foreach (Order order in orders)
{
if (order.TotalPrice > 1000)
{
Console.WriteLine($"订单 {order.Id} 总价为 {order.TotalPrice:C}");
}
}
3. 性能对比:for 与 foreach 的效率
- for 循环:直接操作内存地址,通常更快,适合对性能要求高的场景;
- foreach 循环:通过迭代器实现,开销略高,但代码更清晰,适合简单遍历。
测试代码示例:
int[] largeArray = new int[1000000];
Stopwatch sw = new Stopwatch();
// 测试 for 循环
sw.Start();
for (int i = 0; i < largeArray.Length; i++)
{
// 空操作
}
sw.Stop();
Console.WriteLine($"for 循环耗时:{sw.ElapsedMilliseconds} ms");
// 测试 foreach 循环
sw.Restart();
foreach (var _ in largeArray)
{
// 空操作
}
sw.Stop();
Console.WriteLine($"foreach 循环耗时:{sw.ElapsedMilliseconds} ms");
(注:实际性能可能因环境而异,需结合具体场景选择。)
最佳实践与总结
1. 选择循环的黄金法则
- 选
for
:当需要精确控制索引、处理固定次数的任务,或对性能要求严格时; - 选
foreach
:当只需遍历集合元素,且无需修改集合或索引时。
2. 避免常见陷阱
- 修改集合:在
for
循环中修改集合(如删除元素)可能导致索引错误,需谨慎处理; - 迭代器失效:在
foreach
中直接修改集合会抛出异常,可考虑先复制为临时列表。
3. 结论
掌握 C# for/foreach 循环是成为高效 C# 开发者的必经之路。通过理解两者的语法差异、性能特点和适用场景,开发者可以编写出既清晰又高效的代码。无论是构建基础功能还是优化复杂逻辑,合理选择循环结构都能显著提升开发效率。
希望本文能帮助你更好地驾驭 C# 的循环工具,让代码在简洁与性能之间找到最佳平衡点!