【问题标题】:Changing Enumerated items aren't changed in original IEnumerable更改枚举项在原始 IEnumerable 中未更改
【发布时间】:2018-05-08 22:17:12
【问题描述】:

我注意到枚举集合的问题是.Select<T>() 的结果,我可以枚举它,并修改集合中的每个项目。当我在枚举完成后查看集合时,每个项目都未修改。

public class FooModel
{
    public Guid? Id { get; set; }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        IEnumerable<FooModel> foos = Enumerable.Range(0, 100)
            .Select(m => new FooModel());

        foreach(FooModel f in foos)
        {
            f.Id = Guid.NewGuid();
        }

        Assert.IsTrue(foos.All(foo => foo.Id.HasValue));
    }
}

如果我附加 .ToList().ToArray() 来执行枚举,那么它会修改集合中的项目。

我知道IEnumerable 不会在.Select&lt;T&gt; 之后执行,但是当foreach 运行时,它会创建一个枚举器并在 foo 本地字段上执行 IEnumerable。为什么它不引用 Select&lt;T&gt; 创建的同一个对象?

我已经看到关于何时使用IEnumerable 而不是List 的问题,但我了解两者之间的区别。或多或少地描述与实施。我的问题更多是关于为什么 foreach 在本地字段上执行 IEnumerable 并且不对本地变量中引用的相同对象进行操作。

【问题讨论】:

标签: c# .net ienumerable


【解决方案1】:

为什么它不引用 Select 创建的同一个对象?

因为foo 正在使用Enumerable.Range 即时枚举。没有您正在迭代的底层数据存储。

当您调用 foreach 时,您正在执行底层查询,它会动态创建 100 个 FooModel 对象,您可以对其进行修改。

当您调用 .All 时,您会再次执行查询,这将创建 另一个 100 个未修改的 Foo 动态对象

当您通过ToListToArray 水合结果时,您将循环具体集合,您对基础对象的更改将持续存在。

【讨论】:

  • 我想知道为什么 Select 有这种副作用,而像 Where&lt;T&gt; 这样的其他 LINQ 方法却没有。这是有道理的,因为Select&lt;T&gt; 会转换对象,而不仅仅是对同一系列对象运行过滤器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-05
  • 2013-11-01
  • 1970-01-01
  • 2012-05-05
相关资源
最近更新 更多