【问题标题】:C# LINQ Multiple evaluation of the same dataC# LINQ 对相同数据的多次评估
【发布时间】:2020-04-16 15:42:39
【问题描述】:

给定一个持有(并初始化一次)IEnumerable<T> 的类:

public class MyClass
{
    public MyClass()
    {
        Values = Sequence(0, 10).Select(i => Convert(i));
    }

    public IEnumerable<string> Values { get; private set; }

    private static string Convert(int i)
    {
        string iStr = i.ToString();
        Console.WriteLine("Convert: " + iStr);
        return iStr;
    }

    private static IEnumerable<int> Sequence(int start, int end)
    {
        return Enumerable.Range(start, end - start + 1);
    }
}

为什么每个需要myClass.Values 评估值的用法都重新评估它们?

例如:

static void Main(string[] args)
{
    MyClass myClass = new MyClass();

    foreach (var v in myClass.Values)
    {
        Console.WriteLine(v);
    }
    foreach (var v in myClass.Values)
    {
        Console.WriteLine("Value: " + v);
    }
}

这将打印 20 次“Convert:”和“Value:”。

我知道将值保存为列表(例如 ToList())可以解决这个问题,但我的理解是,一旦对值进行评估,这些值将从内存中使用(就像我使用了 Lazy&lt;T&gt; 和然后Values.value),为什么不一样呢?

【问题讨论】:

标签: c# linq lazy-evaluation


【解决方案1】:

这是IEnumerable&lt;T&gt; 的正常行为。当在foreach 循环中调用每个项目时,您的投影调用Select 实际上是为集合中的每个项目调用的(但显然您只调用了一次)。

因此,当您使用 foreach 循环时,IEnumerable 对象正在调用枚举器并获取下一项(如果集合中有任何可用的话)类似于状态机。

当下一个项目在 foreach 循环中被请求时,它会跟踪正在枚举的当前项目,它会再次被调用,从而导致再次调用 Convert 方法。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-06
  • 1970-01-01
  • 2018-01-01
  • 1970-01-01
相关资源
最近更新 更多