修改集合中对象的属性

本文关键字:属性 对象 集合 修改 | 更新日期: 2023-09-27 18:27:25

我有一个对象集合,想要修改该集合中对象的属性。如果我有一个对象,那么我的ChangeStuff方法可以很好地工作,并且从该方法返回时会修改该对象。(主线路的前4条线路)

然而,在遍历集合时,我想我遗漏了一些东西,因为我更改的值似乎被卡在foreach循环的范围内。

我不应该通过ref(或使用out参数)传递对象,因为我不会返回新值。

很抱歉有这么大的代码块,但它已经尽我所能简化了,并且仍然展示了我的问题。

    class foobar
    {
        public string string1;
        public string string2;
    }
    static void Main(string[] args)
    {
        /***** THIS WORKS!! *****/
        foobar singleFb = new foobar { string1 = "foo2", string2 = "bar2" };
        ChangeStuff(singleFb);
        Console.WriteLine(singleFb.string1 + ", " + singleFb.string2);
        Console.ReadLine(); //pause to read output
        /***** THIS DOESN'T WORK!! *****/
        List<foobar> myList = new List<foobar> { new foobar {string1 = "foo1", string2 = "bar1"}, new foobar {string1 = "foo2", string2 = "bar2"}, new foobar {string1 = "something else", string2 = "something else again"} };
        IEnumerable<foobar> fbs = myList.Where(x => x.string1.StartsWith("foo"));
        ChangeStuff(fbs);
        foreach (foobar fb in fbs)
        {
            Console.WriteLine(fb.string1 + ", " + fb.string2);
        }
        Console.ReadLine(); //pause to read output
    }
    static void ChangeStuff(IEnumerable<foobar> fbs)
    {
        foreach (foobar fb in fbs)
        {
            ChangeStuff(fb);
        }
    }
    static void ChangeStuff(foobar fb)
    {
        if (fb.string1.Contains("2"))
            fb.string1 = "changed!";
    }
}

为了修改集合中的对象,我需要更改什么


编辑:此外,我刚刚注意到,当我的集合返回时,它实际上完全缺少"foo2"。。。奇怪的实际上,我在应用程序中使用IQueryable,并且没有遇到这个问题。我有所有的对象,只是没有正确修改。不确定这里发生了什么。。。


编辑2:感谢您的回答,现在完全有意义了。如果我按如下方式更改ChangeStuff方法,它会像我预期的那样工作:

    static void ChangeStuff(foobar fb)
    {
        if (fb.string2.Contains("2"))
            fb.string2 = "changed!";
    }

修改集合中对象的属性

您看到的结果是由于IEnumerable<T>的延迟加载特性。第二次枚举"fbs"时,属性"string1"已更改,因此它不再与Where谓词匹配。

如果立即枚举IEnumerable并将结果存储在具体列表中(例如,使用ToList()ToArray(),则第二个枚举将显示您期望的结果:

IEnumerable<foobar> fbs = myList.Where(x => x.string1.StartsWith("foo")).ToList();

以下是代码的原始版本中发生的情况:

List<foobar> myList = new List<foobar> { new foobar { string1 = "foo1", string2 = "bar1" }, new foobar { string1 = "foo2", string2 = "bar2" }, new foobar { string1 = "something else", string2 = "something else again" } };
IEnumerable<foobar> fbs = myList.Where(x => x.string1.StartsWith("foo"));
// here the enumeration yields objects #1 and #2
// object #2 has its "string1" property modified to "changed!"
ChangeStuff(fbs);
// here the enumeration is re-evaluated, and now object #2 no longer matches the predicate
// only object #1 ("foo1") is output
foreach (foobar s in fbs)
{
    Console.WriteLine(s.string1);
}

处理LINQ时需要记住的最重要的一点是,方法不会返回查询的结果,它们返回一个表示查询本身的对象。当枚举序列时,将执行查询并返回项。

fbs是一个查询,用于获取第一个字符串以foo开头的所有项。它不是前两个项目的集合,即使当您第一次定义该查询时,这些项目将被返回

第一次执行查询并迭代结果时,您会返回两个项目并尝试同时更改它们,实际上只有一个项目被ChangeStuff更改。然后再次执行查询以打印结果,但现在更改的项不符合查询的条件,因此不会返回。只返回第一个未更改的项目。如果您迭代列表,而不是查询,您将看到更改后的项。

相关文章: