为什么我必须创建“IEnumerable”的具体实现才能修改其成员?

发布于 2024-12-19 01:45:06 字数 984 浏览 3 评论 0原文

为什么我必须创建 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱花落人离去 2024-12-26 01:45:06

每次迭代 people 时,它都会再次执行 GetPeople() 中的代码 - 创建 Person 的新实例。当您调用 GetPeople() 时,GetPeople 中的代码不会运行;它仅在您调用某些内容时才开始运行:

var iterator = people.GetEnumerator();
iterator.MoveNext();

...这就是 foreach 循环的作用。

如果您调用 ToList(),则意味着您仅执行 GetPeople() 中的代码一次,并存储迭代时返回的引用顺序。此时,每次迭代 List 时,您都会迭代对相同对象的引用,因此您在一个循环中所做的任何修改都将在另一个循环中看到。

您可能会发现,如果将日志记录(或断点)放在 GetPeople() 中,理解发生的情况会稍微容易一些。我有一篇文章,其中介绍了实现细节,这可能也使事情变得更加清晰。

Each time you iterate over people, it will execute the code in GetPeople() again - creating new instances of Person. The code in GetPeople does not run when you call GetPeople(); it only starts running when you call something:

var iterator = people.GetEnumerator();
iterator.MoveNext();

... which is what the foreach loop does.

If you call ToList(), that means you only execute the code in GetPeople() once, and store the references returned when iterating over the sequence. At that point, each time you iterator over the List<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.

终止放荡 2024-12-26 01:45:06

GetPeople 动态创建People。您的第一个 foreach (var item in people) 创建 Peoples,您在那里设置年龄,之后,它们不会存储在任何地方。
您的第二个 foreach (var item in people) 创建了一组新的 people,它们是新的/不同的对象。

GetPeople creates People on the fly. your first foreach (var item in people) creates Peoples, you set there ages, and after that, they are not stored anywhere.
Your second foreach (var item in people) creates a new set of people, they are new/different objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文