为什么我必须创建“IEnumerable”的具体实现才能修改其成员?
为什么我必须创建 IEnumerable
的具体实现才能在 foreach
循环中修改其成员?
这篇博文(图表 1) 解释了的行为,但我无法完全理解它。
我在这里有一个非常简单的代码片段来重现该问题(C# 4.0 / .NET 4.0)。
class Person
{
public int Age { get; set; }
public Person()
{
}
}
class Program
{
static void Main(string[] args)
{
//calling .ToList() on GetPeople() below will fix the issue
var people = GetPeople();
foreach (var item in people)
{
item.Age = DateTime.Now.Second;
}
foreach (var item in people)
{
Console.WriteLine("Age is {0}", item.Age);
}
Console.Read();
}
public static IEnumerable<Person> GetPeople()
{
int i = 0;
while (i < 3)
{
i++;
yield return new Person();
}
}
}
Why do I have to create a concrete implementation of IEnumerable<T>
in order to modify its members in the foreach
loop?
This blog post (Exhibit 1) explains the behavior, but I can't quite wrap my head around it.
I've got a very simple code snippet here to reproduce the issue (C# 4.0 / .NET 4.0).
class Person
{
public int Age { get; set; }
public Person()
{
}
}
class Program
{
static void Main(string[] args)
{
//calling .ToList() on GetPeople() below will fix the issue
var people = GetPeople();
foreach (var item in people)
{
item.Age = DateTime.Now.Second;
}
foreach (var item in people)
{
Console.WriteLine("Age is {0}", item.Age);
}
Console.Read();
}
public static IEnumerable<Person> GetPeople()
{
int i = 0;
while (i < 3)
{
i++;
yield return new Person();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
每次迭代
people
时,它都会再次执行GetPeople()
中的代码 - 创建Person
的新实例。当您调用GetPeople()
时,GetPeople
中的代码不会运行;它仅在您调用某些内容时才开始运行:...这就是 foreach 循环的作用。
如果您调用
ToList()
,则意味着您仅执行GetPeople()
中的代码一次,并存储迭代时返回的引用顺序。此时,每次迭代List
时,您都会迭代对相同对象的引用,因此您在一个循环中所做的任何修改都将在另一个循环中看到。您可能会发现,如果将日志记录(或断点)放在
GetPeople()
中,理解发生的情况会稍微容易一些。我有一篇文章,其中介绍了实现细节,这可能也使事情变得更加清晰。Each time you iterate over
people
, it will execute the code inGetPeople()
again - creating new instances ofPerson
. The code inGetPeople
does not run when you callGetPeople()
; it only starts running when you call something:... which is what the
foreach
loop does.If you call
ToList()
, that means you only execute the code inGetPeople()
once, and store the references returned when iterating over the sequence. At that point, each time you iterator over theList<Person>
you'll iterate over references to the same objects, so any modifications you make in one loop will be seen in another.You may find it slightly easier to understand what's going on if you put logging (or a breakpoint) in
GetPeople()
. I have an article which goes into the implementation details, which may make things clearer too.GetPeople 动态创建
People
。您的第一个foreach (var item in people)
创建Peoples
,您在那里设置年龄,之后,它们不会存储在任何地方。您的第二个
foreach (var item in people)
创建了一组新的people
,它们是新的/不同的对象。GetPeople creates
People
on the fly. your firstforeach (var item in people)
createsPeoples
, you set there ages, and after that, they are not stored anywhere.Your second
foreach (var item in people)
creates a new set ofpeople
, they are new/different objects.