C# foreach() 是否按引用迭代?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1538301/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:34:01  来源:igfitidea点击:

Does foreach() iterate by reference?

c#referenceforeach

提问by sharkin

Consider this:

考虑一下:

List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
    obj.property = 42;
}

Is obja reference to the corresponding object within the list so that when I change the property the change will persist in the object instance once constructed somewhere?

是否是obj对列表中相应对象的引用,以便当我更改属性时,一旦在某处构造,更改将保留在对象实例中?

采纳答案by Brian Rasmussen

Yes, objis a reference to the current object in the collection (assuming MyClassis in fact a class). If you change any properties via the reference, you're changing the object, just like you would expect.

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

Be aware however, that you cannot change the variable objitself as it is the iteration variable. You'll get a compile error if you try. That means that you can't null it and if you're iterating value types, you can't modify any members as that would be changing the value.

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

The C# language specification states (8.8.4)

C# 语言规范规定 (8.8.4)

"The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement."

“迭代变量对应于只读局部变量,其作用域扩展到嵌入语句。”

回答by Charles Bretana

Well, without understanding exactly what you mean by "Iterate by reference", I can't answer specifically yes or no, but I can say that what's going on under the surface is that the .net framework is constructing an "enumerator" class for each time client code calls a foreach, for the life of the foreach, that maintains a reference pointer into the collection being iterated over, and each time your foreach iterates, ir "delivers" one item and "increments" the pointer or reference in the enumerator to the next item...

好吧,如果不完全理解“按引用迭代”的意思,我无法具体回答是或否,但我可以说,表面上发生的事情是 .net 框架正在构建一个“枚举器”类每次客户端代码调用 foreach 时,在 foreach 的生命周期内,它都会维护一个指向正在迭代的集合的引用指针,并且每次您的 foreach 迭代时,ir“传递”一个项目并“增加”指针或引用枚举到下一个项目...

This happens regardless of whether the items in the collection you are iterating over are values types or reference types.

无论您迭代的集合中的项目是值类型还是引用类型,都会发生这种情况。

回答by Stan R.

obj is a reference to an item inside the List, hence if you change it's value it will persist. Now what you should be concerned about is whether or not get_the_list(); is making a deep copy of the List or returning the same instance.

obj 是对 List 内项目的引用,因此如果您更改它的值,它将持续存在。现在你应该关心的是 get_the_list(); 正在制作 List 的深层副本或返回相同的实例。

回答by JaredPar

You've asked 2 different questions here, lets take them in order.

您在这里问了 2 个不同的问题,让我们按顺序回答。

Does a foreach loop iterate by reference?

foreach 循环是否按引用迭代?

If you mean in the same sense as a C++ for loop by reference, then no. C# does not have local variable references in the same sense as C++ and hence doesn't support this type of iteration.

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

Will the change be persisted

更改是否会持续

Assuming that MyClass is a reference type, the answer is yes. A class is a reference type in .Net and hence the iteration variable is a reference to the one variable, not a copy. This would not be true for a value type.

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

回答by Brian Scott

Yes, that's also why you cannot alter the enumerable object in the context of the foreach statement.

是的,这也是您不能在 foreach 语句的上下文中更改可枚举对象的原因。

回答by Deepfreezed

this is true as long as it is not a struct.

只要它不是结构体,这就是正确的。

回答by mrzepa

Well, it happened to me that my changes were not updated in a foreach loop when I iterated through var collection:

好吧,当我遍历 var 集合时,我的更改没有在 foreach 循环中更新:

var players = this.GetAllPlayers();
foreach (Player player in players)
{
    player.Position = 1;
}

When I changed var to List it started working.

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

回答by jaccso

Yes, until you change the generic type from List to IEnumerable..

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

回答by J Keegan

You can in this instance (using a List<T>) but if you were to be iterating over the generic IEnumerable<T>then it becomes dependant on its implementation.

您可以在这种情况下(使用 a List<T>)但是如果您要迭代泛型,IEnumerable<T>那么它就依赖于它的实现。

If it was still a List<T>or T[]for instance, all would work as expected. The big gotcha comes when you are working with an IEnumerable<T>that was constructed using yield. In this case, you can no longer modify properties of Twithin an iteration and expect them to be present if you iterate the same IEnumerable<T>again.

如果它仍然是一个List<T>T[]例如,一切都会按预期工作。当您IEnumerable<T>使用使用 yield 构建的一个时,最大的问题就来了。在这种情况下,您不能再修改T迭代中的属性,并期望如果IEnumerable<T>再次迭代相同的属性,它们会出现。

回答by Wolf

Maybe it's interesting for you to lean that by version C# 7.3 it's possible to change values by reference provided that the enumerator's Currentproperty returns a reference Type. The following would be valid (verbatim copy from the MS docs):

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

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

Read more about this new feature at C# foreach statement | Microsoft Docs.

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