如果我在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;
行执行?如果是,那么它会对性能产生影响吗?最重要的是,我在这里遗漏了什么吗?
答案 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