foreach()是否通过引用迭代?

sha*_*kin 64 c# foreach reference

考虑一下:

List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
    obj.property = 42;
}
Run Code Online (Sandbox Code Playgroud)

'obj'是对列表中相应对象的引用,这样当我更改属性时,更改将在构造到某处的对象实例中持续存在吗?

Bri*_*sen 63

是的,obj是对集合中当前对象的引用(假设MyClass实际上是一个类).如果您通过引用更改任何属性,那么您正在更改对象,就像您期望的那样.

但请注意,您无法更改变量obj本身,因为它是迭代变量.如果你尝试,你会得到一个编译错误.这意味着您不能将其置零,如果您正在迭代值类型,则无法修改任何成员,因为这会更改值.

C#语言规范声明(8.8.4)

"迭代变量对应于只读局部变量,其范围扩展到嵌入语句."

  • @technophile:实际上,如果MyClass是一个结构,你不能修改obj,因为你不允许自己修改迭代变量. (7认同)
  • @Amy:根据语言规范(8.8.4)"迭代变量对应于只读局部变量,其范围扩展到嵌入语句." (2认同)

jac*_*cso 21

是的,直到您将通用类型从List更改为IEnumerable ..

  • 有人在意这个吗? (4认同)
  • 我会进一步解释为什么会这样 (3认同)
  • 我认为这可能与此有关:/sf/answers/564509851/ (2认同)

Jar*_*Par 19

你在这里问过两个不同的问题,让我们按顺序排列.

foreach循环是否通过引用迭代?

如果你的意思与C++ for while循环相同,那么没有.C#没有与C++相同的局部变量引用,因此不支持这种类型的迭代.

这种变化会持续下去吗?

假设MyClass是一个引用类型,答案是肯定的.类是.Net中的引用类型,因此迭代变量是对一个变量的引用,而不是副本.对于值类型,情况并非如此.


mrz*_*epa 15

好吧,当我迭代var collection时,我的更改在foreach循环中没有更新:

var players = this.GetAllPlayers();
foreach (Player player in players)
{
    player.Position = 1;
}
Run Code Online (Sandbox Code Playgroud)

当我将var更改为List时,它开始工作.


小智 7

你可以在这个例子中(使用a List<T>),但如果你要迭代泛型,IEnumerable<T>那么它就会依赖于它的实现.

如果它仍然是一个List<T>或者T[]例如,所有都将按预期工作.当你IEnumerable<T>使用yield构建的时候,就会遇到大问题.在这种情况下,您不能再修改T迭代中的属性,并且如果IEnumerable<T>再次迭代它们,则期望它们存在.


Wol*_*olf 6

也许你觉得在 C# 7.3 版本中可以通过引用更改值,前提是枚举器的Current属性返回引用类型。以下内容是有效的(来自 MS 文档的逐字副本):

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
Run Code Online (Sandbox Code Playgroud)

C# foreach 语句中阅读有关此新功能的更多信息 | 微软文档