首页 > 解决方案 > IEnumerable和。Linq 方法的行为在哪里?

问题描述

我以为我什么都知道,IEnumerable<T>但我只是遇到了一个我无法解释的案例。当我们在 a 上调​​用 .Where linq 方法时IEnumerable,执行会延迟到枚举对象为止,不是吗?

那么如何解释下面的示例:

public class CTest
{
    public CTest(int amount)
    {
        Amount = amount;
    }

    public int Amount { get; set; }

    public override string ToString()
    {
        return $"Amount:{Amount}";
    }

    public static IEnumerable<CTest> GenerateEnumerableTest()
    {
        var tab = new List<int> { 2, 5, 10, 12 };

        return tab.Select(t => new CTest(t));
    }
}

到目前为止没有什么不好的!但是下面的测试给了我一个意想不到的结果,尽管我知道IEnumerable<T>.Wherelinq 方法:

[TestMethod]
public void TestCSharp()
{
    var tab = CTest.GenerateEnumerableTest();

    foreach (var item in tab.Where(i => i.Amount > 6))
    {
        item.Amount = item.Amount * 2;
    }

    foreach (var t in tab)
    {
        var s = t.ToString();
        Debug.Print(s);
    }
}

选项卡中的任何项目都不会乘以 2。输出将是: Amount:2 Amount:5 Amount:10 Amount:12

有谁可以解释为什么在枚举选项卡后,我得到了原始值。 当然,.ToList()在调用GenerateEnumerableTest()方法之后调用一切正常。

标签: c#linqienumerable

解决方案


var tab = CTest.GenerateEnumerableTest();

tab是一个 LINQ 查询,它生成的CTest实例从int-value 初始化,这些 -values 来自一个永远不会改变的整数数组。因此,每当您要求此查询时,您都会得到“相同”的实例(与原始实例Amount)。

如果您想“实现”此查询,您可以使用ToList然后更改它们。否则,您正在修改CTest仅存在于第一个foreach循环中的实例。第二个循环CTest使用未修改的 枚举其他实例Amount

因此查询包含如何获取项目的信息,您也可以直接调用该方法:

foreach (var item in CTest.GenerateEnumerableTest().Where(i => i.Amount > 6))
{
    item.Amount = item.Amount * 2;
}

foreach (var t in CTest.GenerateEnumerableTest())
{
   // now you don't expect them to be changed, do you?
}

推荐阅读