如果之后更新了源,为什么linq结果会更新?

时间:2015-03-12 09:08:00

标签: c# linq collections

我有一个整数值列表;

var items= new List<int>();
items.Add(1);
items.Add(8);
items.Add(14);
items.Add(11);
var sequel=from i in items where i >10 select i;
items[1]=25;
Foreach(var c in sequel)
    Console.WriteLine(c);

输出为25 14 11

在我看来,输出应该是14,11。但是,输出实际上是25,14,11。

我的问题是为什么在执行此声明“items [1] = 25;”之后编译器更新“续集”的原因?  在我看来,这些集合是不同的,没有连接。请澄清。

更新:

是的,我读到延迟执行,我的第一个想法是它确实存在。 但是,在调试模式下,我在声明之前看到续集是“14,11”:

items[1]=25;

然后,在此声明之后,“续集”变为“25,14,11”。那么为什么编译器会重新制作查询呢?

5 个答案:

答案 0 :(得分:3)

因为LINQ使用延迟执行。这意味着:

from i in items where i >10 select i;

您只是构建查询。除非您使用foreach迭代结果或使用迭代查询的方法(例如ToListToArray,否则它不会被执行。这就是为什么当您更改项目时,查询运行在改变版本上。

有关延迟执行和延迟加载的更多信息,请参阅以下文章:

更新:在Debug模式下,您实际上评估查询以查看结果。这是在更改项目之前发生的。sequel没有任何数字,它只是一个查询。没有别的,你只能将数字存储到一个集合,如List,你在调试器中看到的东西只是一个功能,允许你立即评估查询和显示你的结果。

答案 1 :(得分:2)

这在LINQ中称为Deferred execution。根据MSDN: -

  

立即返回值是存储所有内容的对象   执行操作所需的信息。查询   直到对象为止,才执行此方法表示的方法   通过直接调用其GetEnumerator方法或通过调用来枚举   使用foreach

为了获得所需的输出,您需要使用ToList()ToArray来实现您的查询: -

var sequel=(from i in items where i >10 select i).ToList();

<强>更新

好的,你必须通过Results View在调试模式中看到结果吗?因此,只需检查用它给出的描述,Visual Studio说:

  

扩展结果将枚举IEnumarable

因此,只是为了在调试模式中查看目的,它枚举而不是实际。

答案 2 :(得分:1)

Linq迭代现有的集合 - 它不会复制该集合。如果该集合的内容发生更改,则迭代中的项目将更改。

此外,Linq使用&#34;延迟执行&#34;模型,只有在迭代Linq提供的IEnumerable时才会访问集合中的项目。

如果您想要制作该集合的副本,您可以明确地执行此操作,如下所示:

var sequel=(from i in items where i >10 select i).ToArray();

您也可以使用.ToList()

答案 3 :(得分:1)

这是因为LINQ中的懒惰评估。它被称为“延迟执行”,意味着只有在items循环迭代时才会将条件应用于foreach

您的sequel变量有WhereListIterator类型。因此,如果您想立即执行,您只需要按ToList()ToArray()迭代此查询:

var sequel = (from i in items where i > 10 select i).ToList();

您的sequel变量将获得List类型,您可以通过以下方式设置项目值:

sequel[1] = 25;

在输出中,您将获得14和25个数字。

更改items不会影响sequel,因为它是值类型对象的不同集合。

答案 4 :(得分:0)

LINQ具有所谓的延迟执行,这意味着它会根据您的需要在Foreach上加载数据。

看起来像这样:如果你编写一个SQL语句,但没有执行它,它就不会对数据做任何事情。这完全一样。

更多信息,请参阅此处:http://www.codeproject.com/Articles/692847/THREE-Examples-of-Deferred-vs-I