有趣的行为:LINQ查询带整数

时间:2013-07-31 10:13:21

标签: c# linq

如果我在LINQ where子句中使用任何整数变量,并且在查询执行后如果我修改/初始化整数变量,那么LINQ查询的结果集会发生变化。例如:

static void Main(string[] args)
{    
     int startPos = 0;          
     List<string> intList = new List<string>();
     for (int i = 0; i < 10; i++)
     {
        intList.Add(i.ToString());
     }

     var qResult = from c in intList
                   where Convert.ToInt32(c) >= startPos
                   select c;

     // prints count as 10
     Console.WriteLine("List count is :"+qResult.Count());

     startPos = 5;

     // prints count as 5
     Console.WriteLine("List count is :" + qResult.Count());
}

输出:

List count is :10
List count is :5

在上面的示例中,您可以看到startPos = 5;后,qResult已更改。我不明白这是怎么发生的;据我所知,int是值类型。

Linq查询是否再次在第startPos = 5;行执行?如果是,那么它会对性能产生影响吗?最重要的是,我在这里遗漏了什么吗?

5 个答案:

答案 0 :(得分:2)

每次拨打qResult时,

.Count()都会枚举,因此当您在调用startPos之间更改.Count()时,您实际上正在改变正在执行的代码。

要避免这种情况,请拨打.ToList().ToArray()或类似内容列举您的列表一次:

List<string> qResult = (from c in intList
                   where Convert.ToInt32(c) >=startPos
                   select c).ToList();

This是关于LINQ中延迟执行的非常好的文章。

答案 1 :(得分:1)

这是因为qResult将是IEnumerable<T>,并在您每次致电.Count()时执行。如果您希望结果永远不会改变,只需使用ToList(),如下所示:

var qResult = (from c in intList
               where Convert.ToInt32(c) >=startPos
               select c).ToList();

答案 2 :(得分:0)

.Count()在调用时执行枚举。它不像变量值,因此结果与预期行为一致。

答案 3 :(得分:0)

linq查询在调用时执行,因为它使用延迟加载,在您的情况下,您的查询在qResult.Count()中执行,如果您希望强制执行调用ToList()或类似函数

答案 4 :(得分:0)

是的,这是因为每次调用qResult并且您正在访问linq查询中的已修改closure 时,Count()都会被枚举。您应该使用第三个变量来避免此行为:

        int pos = startPos;
        var qResult = from c in intList
                      where Convert.ToInt32(c) >= pos
                      select c;

或枚举到位:

        var qResult = (from c in intList
                      where Convert.ToInt32(c) >= startPos
                      select c).ToArray();

它被称为deffered execution