LinQ在C#中,为什么查询语句必须转换为tolist()?

时间:2014-11-06 08:47:01

标签: c# linq

我有以下代码:

class Program
{
    private static List<Member> members = new List<Member>
    {
        new Member() {m_FirstName = "Chiristopher", m_LastName="Harrison"},
        new Member() {m_FirstName = "Jeremy", m_LastName =  "Foster"},
        new Member() {m_FirstName = "Stacey", m_LastName = "Mulcahy"}
    };
    static void Main(string[] args)
    {
        var result = (from m in members
                     where m.m_LastName.Length > 6
                     select m);


        Console.WriteLine("** First Execution **");

        foreach(var member in result)
        {

            Console.WriteLine(member);
        }

        members.Add(new Member() { m_FirstName = "Rian", m_LastName = "ThyTuhfadsl" });

        Console.WriteLine("** Second Execution **");

        foreach (var member in result)
        {
            Console.WriteLine(member);
        }
    }
}

当我建造它时: 安慰: **首次执行** Chiristopher Harrison 史黛西马尔卡希 **第二次执行** Chiristopher Harrison 史黛西马尔卡希 Rian ThyTuhfadsl

如果我调试,结果变量在第一个时有3个值,但它只打印两个值。为什么呢?

并且在第二个,是四个值。虽然,我不会重新键入任何代码

如果我输入

var result = (from m in members
                     where m.m_LastName.Length > 6
                     select m).toList();

在任何情况下只有两个值。

6 个答案:

答案 0 :(得分:1)

因为linq查询被懒惰地评估了。大多数linq查询方法都返回一个Iterator变量。迭代器仅在您使用foreach调用迭代时执行某些方法,例如ToArrayToList迭代结果并将它们添加到列表中。

答案 1 :(得分:1)

linq查询可以是几种类型,如.NET中所定义:

  • IEnumerable<T> for linq-to-objects
  • IQueryable<T> for linq-to-sql
  • 对于PLINQ
  • ParallelQuery<T>
  • 等......

在您的情况下,您使用的是linq-to-objects,因此result变量的类型为IEnumerable<Member>。这被定义为一个可枚举的序列,在您实际枚举它之前,它不一定具体化。这就是这里发生的事情。请参阅my answer here,其中详细介绍了可用数据。

我们说该查询是懒惰评估的。第二次枚举它时,会重新评估它。如果您致电.ToList(),您将只实现一次查询并获取一个列表,这将在两个枚举中产生相同的结果。

答案 2 :(得分:0)

这是“延迟执行”的一部分,您可以在线搜索。

在需要之前不会执行查询。 (只有当你迭代它时)。

'.tolist()'命令强制执行查询。

答案 3 :(得分:0)

这与linq查询的延迟评估有关。如果您在linq查询之后编写ToList(),则会立即对其进行评估和实现。如果您不编写ToList(),则仅在确实需要时才评估查询。

答案 4 :(得分:0)

在您的第一个代码示例中,您将枚举原始列表两次。

但是当您用上一个代码示例替换LINQ查询时,您可以复制原始序列。 LINQ方法ToList将序列的副本复制到List<T>实例中。 因此,在这种情况下,您将枚举序列的副本两次,同时更改原始列表。

答案 5 :(得分:0)

if I debug, result variable has 3 values at the first,

除了其他人所说的内容,如果我正确理解你的问题,你所说的关于结果的3个值指的是source属性还没有实现,因为它只是

的一个实例
  private class WhereListIterator<TSource> : Enumerable.Iterator<TSource>
    {
      private List<TSource> source;
      private Func<TSource, bool> predicate;
      private List<TSource>.Enumerator enumerator;

所以你的代码是正确的

enter image description here