Gia*_*971 50 c# iteration foreach accessor
我只是对此感到好奇:以下代码无法编译,因为我们无法修改foreach迭代变量:
foreach (var item in MyObjectList)
{
item = Value;
}
Run Code Online (Sandbox Code Playgroud)
但是以下将编译并运行:
foreach (var item in MyObjectList)
{
item.Value = Value;
}
Run Code Online (Sandbox Code Playgroud)
为什么第一个无效,而第二个可以在下面做同样的事情(我正在为此寻找正确的英语表达,但我不记得了.在...下面??^^)
Moh*_*bed 36
foreach是一个只读迭代器,它动态迭代实现IEnumerable的类,foreach中的每个循环都会调用IEnumerable来获取下一个项目,你拥有的项目是只读参考,你不能重新分配它,但只是调用item.Value
是访问它并为读/写属性分配一些值,但仍然是项目的引用只读参考.
Jon*_*eet 34
第二个是完全没有做同样的事情.它不会改变item
变量的值- 它正在改变该值所引用的对象的属性.如果是一个可变值类型,这两个只是等价的item
- 在这种情况下你应该改变它,因为可变值类型是邪恶的.(他们的表现方式是粗心的开发人员可能没有想到的各种方式.)
它与此相同:
private readonly StringBuilder builder = new StringBuilder();
// Later...
builder = null; // Not allowed - you can't change the *variable*
// Allowed - changes the contents of the *object* to which the value
// of builder refers.
builder.Append("Foo");
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅有关参考和值的文章.
Jam*_*son 22
在枚举时,您无法修改集合.第二个示例仅更新对象的属性,这是完全不同的.
for
如果需要在集合中添加/删除/修改元素,请使用循环:
for (int i = 0; i < MyObjectList.Count; i++)
{
MyObjectList[i] = new MyObject();
}
Run Code Online (Sandbox Code Playgroud)
Wou*_*ort 11
如果你看一下语言规范,你可以看出为什么这不起作用:
规范说foreach扩展为以下代码:
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
Run Code Online (Sandbox Code Playgroud)
如您所见,当前元素用于调用MoveNext().因此,如果您更改当前元素,则代码将"丢失"并且无法迭代集合.因此,如果您看到编译器实际生成的代码,那么将元素更改为其他内容就没有任何意义.
这将有可能使item
可变的。我们可以更改代码的生成方式,以便:
foreach (var item in MyObjectList)
{
item = Value;
}
Run Code Online (Sandbox Code Playgroud)
等效于:
using(var enumerator = MyObjectList.GetEnumerator())
{
while(enumerator.MoveNext())
{
var item = enumerator.Current;
item = Value;
}
}
Run Code Online (Sandbox Code Playgroud)
然后它将进行编译。但是,它不会影响收集。
还有摩擦。代码:
foreach (var item in MyObjectList)
{
item = Value;
}
Run Code Online (Sandbox Code Playgroud)
人类有两种合理的方式去考虑它。一个就是那item
只是一个占位符,更改它与更改位置没有什么不同item
:
for(int item = 0; item < 100; item++)
item *= 2; //perfectly valid
Run Code Online (Sandbox Code Playgroud)
另一个是更改项目实际上会更改集合。
在前一种情况下,我们可以将项目分配给另一个变量,然后进行处理,因此不会有任何损失。在后一种情况下,这是既禁止(或者至少,你不能指望改变的集合,而通过它迭代,虽然它不具备对所有普查员执行),并在许多情况下无法提供(视的性质)。
即使我们认为前一种情况是“正确的”实现,人类也可以以两种不同的方式对其进行合理解释这一事实足以避免这种情况,尤其是考虑到在任何情况下我们都可以轻松解决这一问题。