foreach()是否通过引用迭代?
考虑一下:
List<MyClass> obj_list = get_the_list(); foreach( MyClass obj in obj_list ) { obj.property = 42; }
'obj'是对列表中相应对象的引用,所以当我改变属性的时候,这个改变会一直存在于对象实例中。
是的, obj
是对集合中当前对象的引用(假设MyClass
实际上是一个类)。 如果您通过引用更改任何属性,那么您正在更改对象,就像您期望的那样。
但是,请注意,您不能更改variablesobj
本身,因为它是迭代variables。 如果你尝试,你会得到一个编译错误。 这意味着你不能清空它,如果你正在迭代值types,你不能修改任何成员,因为这将改变价值。
C#语言规范规定(8.8.4)
“迭代variables对应于一个只读局部variables,其范围覆盖embedded语句。”
是的,直到你从通用types更改为IEnumerable ..
你问了两个不同的问题,让我们把它们按顺序。
一个foreach循环是否通过引用迭代?
如果你的意思是与C ++ for循环引用相同的意思,那么没有。 C#没有像C ++那样的局部variables引用,因此不支持这种types的迭代。
这个变化是否会持续下去?
假设MyClass是一个引用types,答案是肯定的。 类是.Net中的引用types,因此迭代variables是对一个variables的引用,而不是副本。 值types不适用。
那么,我碰巧发现,当我通过var collection进行迭代时,我的更改没有在foreach循环中更新:
var players = this.GetAllPlayers(); foreach (Player player in players) { player.Position = 1; }
当我将var更改为List时,它开始工作。
你可以在这个例子中(使用List<T>
),但是如果你要迭代genericsIEnumerable<T>
那么它就会依赖于它的实现。
如果它仍然是一个List<T>
或T[]
,例如,所有将按预期工作。 当你使用一个使用yield构造的IEnumerable<T>
时,会遇到一个大问题。 在这种情况下,如果您再次迭代相同的IEnumerable<T>
,则不能再在迭代中修改T
属性,并期望它们存在。
只要它不是一个结构就是这样。
那么,如果没有完全理解“按引用迭代”的含义,我不能具体回答是或否,但是我可以说在表面下发生的事情是.NET框架正在构build一个“枚举器”类每次客户端代码调用一个foreach,在foreach的生命周期中,维护一个引用指针到被迭代的集合中,并且每当你的foreach迭代时,ir“递送”一个项目,并且“增加”指针或者引用枚举器到下一个项目…
无论您正在迭代的集合中的项目是值types还是引用types,都会发生这种情况。
obj是对List中的一个项目的引用,因此如果你改变它的值,它将会持续。 现在你应该关心的是get_the_list(); 正在制作List的深层副本或返回相同的实例。
是的,这也是为什么你不能在foreach语句的上下文中改变可枚举对象的原因。