List(T).ForEach 或 Foreach,区别大吗?






4.31/5 (22投票s)
使用 List 时,使用泛型列表的 ForEach 方法与使用普通的 foreach 循环,区别大吗?有时确实有区别!
引言
在 C# 中,有多种方法可以迭代列表,例如 `for` 循环、`foreach` 循环或 LINQ。当使用 `List(T)` 类型时,还有一个 `ForEach` 方法。但此方法并不总是与普通的 `foreach` 循环表现相同。
Using the Code
`List
修改对象本身
下面的示例使用 `ForEach` 方法遍历集合中所有存储的 `Points`。它从点的 x 坐标减去 10。最后,`Points` 将被打印到控制台。
List<Point> points = new List<Point>(){ new Point(14, 10), new Point(19, 10) };
items.ForEach(point => point.X = point.X - 10);
foreach (Point point in points)
{
Console.WriteLine(point);
}
在这种情况下,控制台输出为 {X=14, Y=10} 和 {X=19, Y=10}。我期望 X 为 4 和 9,所以哪里错了?如果你将相同的逻辑放入普通的 `foreach` 语句中,编译器会抛出以下错误:“无法修改 'point' 的成员,因为它是一个 'foreach' 迭代变量”。如果我们定义自己的类型,代码就会按预期执行!
public class MyPoint
{
public MyPoint(int x, int y){ X = x; Y = y; }
public int X{ get; set; }
public int Y{ get; set; }
}
List<MyPoint> points = new List<MyPoint>(){ new MyPoint(14, 10), new MyPoint(19, 10) };
items.ForEach(point => point.X = point.X - 10);
foreach (MyPoint point in points)
{
Console.WriteLine(point);
}
区别在于,`Point` 是值类型(结构体),而 `MyPoint` 是引用类型。因此,当使用 `Point` 时,对象的副本被传递给方法,而不是对象本身。因此,如果传递给 `ForEach` 方法的操作更改了副本,它不会影响原始对象。
修改集合
当使用普通的 `foreach` 语句时,你不能在迭代集合时添加或删除项目。但是使用 `List.ForEach` 你可以,因此以下代码可以执行而不会出现任何错误。你期望什么结果?
public class Integer
{
public int Value { get; set; }
public Integer(int value) { Value = value; }
}
public void Sample()
{
List<Integer> items = new List<Integer>()
{
new Integer(14),
new Integer(0),
new Integer(19)
};
items.ForEach(item =>
{
if (item.Value == 0)
{
items.Remove(item);
}
item.Value = item.Value - 10;
});
foreach (Integer item in items)
{
Console.WriteLine(item.Value);
}
}
控制台显示的结果是 4 和 19。这是一个很好的例子,说明并非所有你可以做的事情都应该去做!结果应该是 4 和 9!看起来内部使用了 `for` 循环,它向后迭代集合。
关注点
因此,`List