LINQ with Console.WriteLine

时间:2018-02-25 16:27:22

标签: c# linq ienumerable

文件包含一些字符串,例如:

  

abc 4 2

     

def 1 1 1

     

Gh 0

有一些LINQ功能, 这个功能的细节并不那么重要

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; });
}

此功能不会向控制台输出任何内容。 为什么呢?

2 个答案:

答案 0 :(得分:6)

您必须具体化序列才能使其运行:

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; })
        .ToList();
}

相关说明,建议不要在LINQ表达式中引起副作用。如果此代码用于调试目的,那么它没关系。但是如果你打算将它留待将来使用,那么我建议你从LINQ表达式中删除Console.Write

我们不应该在表达式中引起副作用的原因是大多数LINQ运算符都是惰性求值的。反过来,这样做是为了通过仅评估有效请求的序列的那些元素来提高性能。现在,如果评估会产生副作用,那么如果对同一个懒惰序列进行多次评估,这些影响可能会发生几次 - 这可能不是您想要发生的事情。

答案 1 :(得分:4)

这是延迟执行。

只有您实际枚举结果时才会执行语句。

例如:

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; });
}

void Main()
{
    foreach(var r in F()) //the result is enumerated and will execute the select
    {
         //do stuff
    }
}

见其他问题:

Deferred execution in C#

MSDN example

What are the benefits of a Deferred Execution in LINQ?

如果你打电话给F().ToList(),也会发生同样的事情。

如果枚举本身需要大量资源,则此行为尤其有用。有时,底层框架能够在稍后阶段优化枚举。

例如,如果您要调用以下内容,智能交互操作员或表达式构建器将能够优化:

F().Where(c => ....)