Wei*_*Liu 2 c# linq foreach ref
在什么情况下 foreach 使用引用,在什么情况下 foreach 使用副本?
using System;
using System.Linq;
class A {
public int v;
}
class Program
{
static void Main() {
var ints = new int[] { 0, 1, 2 };
var array = ints.Select(i=>new A {v = i}).ToArray();
foreach(var a in array) {
a.v = 999;
}
var enumerable = ints.Select(i=>new A {v = i});
foreach(var a in enumerable) {
a.v = 999;
}
Console.WriteLine($"array.First = {array.First().v}");
Console.WriteLine($"enumerable.First = {enumerable.First().v}");
}
}
Run Code Online (Sandbox Code Playgroud)
jdoodle.com/ia/Jce
输出:
array.First = 999
enumerable.First = 0
Run Code Online (Sandbox Code Playgroud)
似乎在foreach(var a in enumerable) {a 中是复制而不是引用,而在foreach(var a in array) {a 中是引用。
有人可以解释一下吗?
这并不是真的foreach。它更多地与你如何构造array和有关enumerable。foreach在这两种情况下都执行相同的操作(获取枚举器并调用MoveNextandCurrent迭代可枚举值)。正是enumerable和之间的差异array导致了输出的差异。
array是一个A[],所以如果你改变v它的元素的 s ,然后获取这些元素的第一个,你会明显看到变化。A是引用类型,因此ainforeach是对数组中元素的引用。
enumerable然而,是由 产生的东西Select。如果您只是打电话,不会做任何实质性的事情Select。它只是创建一个IEnumerable<A>,当枚举 时,会创建一堆A对象。这里重要的一点是,每当枚举Select时都会运行 lambda 。enumerable如果您不枚举它,则不会发生任何事情。这称为延迟执行。
所以第二个foreach枚举enumerable,创建一堆A对象,然后更改v这些对象的 s A。这是重要的区别 -A与数组不同,对象不会存储在任何地方。A每次迭代后您都会“丢弃”该对象。
当您enumerable.First()最后调用时,您将enumerable再次开始枚举 - 这次只枚举一次,因为您只需要第一个元素。做什么呢enumerable?A它通过运行 中的代码创建一个新对象Select。
| 归档时间: |
|
| 查看次数: |
364 次 |
| 最近记录: |