为什么我必须创建' IEnumerable '的具体实现才能修改其成员?
本文关键字:实现 修改 成员 创建 IEnumerable 为什么 | 更新日期: 2023-09-27 18:16:07
为什么我必须创建IEnumerable<T>
的具体实现才能在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();
}
}
}
每次迭代people
时,它将再次执行GetPeople()
中的代码-创建Person
的新实例。当你调用GetPeople()
时,GetPeople
中的代码不运行;只有当你调用一些东西时它才会开始运行:
var iterator = people.GetEnumerator();
iterator.MoveNext();
…这就是foreach
循环的作用。
如果您调用ToList()
,这意味着您只执行GetPeople()
中的代码一次,并存储迭代序列时返回的引用。此时,每次在List<Person>
上迭代时,都将迭代对相同对象的引用,因此在一个循环中所做的任何修改将在另一个循环中看到。
如果在GetPeople()
中添加日志记录(或断点),您可能会发现更容易理解发生了什么。我有一篇关于实现细节的文章,可能也会让事情变得更清楚。
GetPeople动态创建People
。你的第一个foreach (var item in people)
创建Peoples
,你设置它们的年龄,之后,它们不存储在任何地方。您的第二个foreach (var item in people)
创建了一组新的people
,它们是新的/不同的对象。