通过linq访问时,将重新创建枚举数的Linq

问题描述 投票:2回答:2

我试图理解下面的代码出了什么问题。

    var signals = new List<List<double>>
    {
        new List<double> {1, 2, 3},
        new List<double> {2, 3, 4},
    };

    var enumerators = signals.Select(l => l.GetEnumerator()).ToList();

    if (enumerators.All(enumerator => enumerator.MoveNext()))
    {
        var cummulative = enumerators.Sum(enumerator => enumerator.Current);
    }

为什么两个枚举数都指向当前值0?我希望两者都指向列表中的第一个数字,分别为1和2。

每次我通过linq访问枚举器时,它似乎都重新启动。为什么?

c# linq enumerator
2个回答
0
投票

根据下面更改代码

var enumerators = signals.Select(l => l.GetEnumerator() as IEnumerator<double>).ToList();

根据此SO post

这是因为List的枚举数是一个结构,而Array的枚举数是一个类。

因此,当您使用struct调用Enumerable.All时,将创建枚举数的副本并将其作为参数传递给Func,因为结构是按值复制的。因此,将在副本上调用e.MoveNext,而不是原始副本。


0
投票

根据docs

最初,枚举器位于中的第一个元素之前集合。在此位置,Current属性未定义。因此,必须调用MoveNext方法来推进枚举器到集合的第一个元素,然后再读取Current

此外,要获得预期的行为和总和,您可以编写以下内容

var cumulative = 0d;
foreach (var enumerator in enumerators)
{
    if (enumerator.MoveNext())
        cumulative += enumerator.Current;
}

All仅返回bool值,它不会更改源序列,因此也不会返回它。

每次我通过linq访问枚举器时,它似乎都重新启动。为什么?

Enumerator<T>struct和值类型,它不是类。每次修改时,都修改副本

© www.soinside.com 2019 - 2024. All rights reserved.