考虑一下:
List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
obj.property = 42;
}
'obj'是否是对列表中相应对象的引用,这样当我更改属性时,更改将在构造到某处的对象实例中持续存在?
答案 0 :(得分:60)
是的,obj
是对集合中当前对象的引用(假设MyClass
实际上是一个类)。如果您通过引用更改任何属性,那么您正在更改对象,就像您期望的那样。
但请注意,您无法更改变量obj
本身,因为它是迭代变量。如果你尝试,你会得到一个编译错误。这意味着您不能将其置零,如果您正在迭代值类型,则无法修改任何成员,因为这会更改值。
C#语言规范声明(8.8.4)
“迭代变量对应于 带有一个只读的局部变量 范围扩展到嵌入式 语句“。
答案 1 :(得分:21)
是的,直到您将通用类型从List更改为IEnumerable ..
答案 2 :(得分:19)
你在这里问过两个不同的问题,让我们按顺序排列。
如果你的意思与C ++ for循环相同,那么没有。 C#没有与C ++相同的局部变量引用,因此不支持这种类型的迭代。
假设MyClass是引用类型,答案是肯定的。类是.Net中的引用类型,因此迭代变量是对一个变量的引用,而不是副本。对于值类型,情况并非如此。
答案 3 :(得分:15)
好吧,当我迭代var collection时,我的更改在foreach循环中没有更新:
var players = this.GetAllPlayers();
foreach (Player player in players)
{
player.Position = 1;
}
当我将var更改为List时,它开始工作。
答案 4 :(得分:6)
你可以在这个例子中(使用List<T>
),但如果你要迭代通用IEnumerable<T>
,那么它就会依赖于它的实现。
例如,如果它仍然是List<T>
或T[]
,则所有内容都会按预期工作。
当您使用使用yield构造的IEnumerable<T>
时,会出现大问题。在这种情况下,您不能再在迭代中修改T
的属性,并且如果再次迭代相同的IEnumerable<T>
,则期望它们存在。
答案 5 :(得分:3)
只要它不是结构,就是这样。
答案 6 :(得分:2)
好吧,如果没有完全理解你的意思是“通过引用迭代”,我不能具体回答是或否,但我可以说,表面下发生的是.net框架正在构建一个“枚举器” “每次客户端代码调用foreach时的类,对于foreach的生命,维护一个引用迭代的集合中的引用指针,每次你的foreach迭代,ir”传递“一个项目并”递增“指针或在枚举器中引用下一个项目......
无论您正在迭代的集合中的项是值类型还是引用类型,都会发生这种情况。
答案 7 :(得分:2)
对于您来说有趣的是,在C#7.3版中,只要枚举器的 Current 属性返回引用类型,就可以通过引用更改值。以下内容将是有效的(MS文档的普通照会副本):
Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
item = num++;
}
在此了解有关此新功能的更多信息 C# foreach statement | Microsoft Docs。
答案 8 :(得分:0)
obj是对List内部项目的引用,因此如果您更改它的值,它将保持不变。 现在您应该关注的是get_the_list();正在制作列表的深层副本或返回相同的实例。
答案 9 :(得分:0)
是的,这也是为什么你不能在foreach语句的上下文中改变可枚举对象的原因。