【问题标题】:Is a Linq-Query called toList() generating copies of the contained elements?一个名为 toList() 的 Linq-Query 是否会生成包含元素的副本?
【发布时间】:2016-06-23 12:47:46
【问题描述】:

我遇到了(对我而言)奇怪的行为。代码如下:

var objects = from i in items
              //some calculations
              select something;

// other calculations

objects.ToList().ForEach(x => {
    //some calculations
    x.Property = "some text"
});

return objects;

首先我生成一个IEnumerable,它是对数据库的查询,我跳过了细节。 然后我必须进行其他计算,最后我遍历我的对象以设置更多参数。运行此代码,一旦返回 IEnumerable 对象,它们的 Property 就不会被设置。

否则,如果我在 Linq 表达式中移动 ToList(),如下所示,Property 被设置:

var objects = (from i in items
              //some calculations
              select something).ToList();

// other calculations

objects.ForEach(x => {
    //some calculations
    x.Property = "some text"
});

return objects;

据我所知,对象不是复制的,而是引用的……对吧? 显然代码背后发生了什么?有什么区别?

【问题讨论】:

  • 当您执行objects.ToList() 时,查询将被执行。然后你返回objects。假设有人随后迭代了返回的对象:在这种情况下,查询将再次执行(因此将创建新对象)
  • var objects without ToList 只是一个查询,所以定义不是执行。如果你实现它,例如使用ToList 或forach,它就会被执行。因此,通过附加ToList,可以查询数据库并填充内存列表。 List.ForEach 将枚举它们并修改属性。在第一种方法中,该列表被立即丢弃,因为它没有存储在变量中。第二个版本是正确的。
  • @TimSchmelter 你能否解释一下“这个列表被立即丢弃,因为它没有存储在变量中”?即使它没有在变量定义上实现,也不应该在执行 ToList 或 ForEach 后将结果存储在 objects 变量中吗?
  • @NahuelIanni:不,objects 变量仍然只是数据库查询。该列表未存储在任何地方。另一种可能更好的方法是将文本分配给查询本身的属性。那么之后就不需要循环列表了。

标签: c# linq


【解决方案1】:

请记住,Linq 查询只是一个查询 - 它的意思是“如果我要此数据,这就是我想要的_。它不保存任何数据,但会等到您询问_结果(通过 foreach,@ 987654322@、ToArray等)

不同之处在于您没有捕获第一个示例中ToList 返回的列表。它被ForEach 调用使用,但objects 变量仍保留对原始查询 的引用。当您再次请求时 - 它会再次获取数据。当它再次获取数据时,会创建新对象。

所以在这方面 - 是的 ToList() 创建一个新列表。它不会修改调用它以将其转换为列表的对象。

在您的第二个示例中,objects 变量包含对通过ToList() 查询生成的列表 的引用,因此当您修改它们并返回objects 时,您将返回相同的列表。

【讨论】:

  • @Taemyr 我认为你是不理解的人。我和 DStanley 在我们的回答中所写的正是正在发生的事情。
  • @DStanley 第一次编辑带来了显着的改进。虽然我更喜欢一个明确表明新项目是由选择创建的答案。
【解决方案2】:

在您的第一个代码示例中,objects.ToList() 实际上正在创建一个您正在使用ForEach 处理的List 类型的新对象。在ForEach 完成后,您仍然只是返回您的IEnumerable,而您真正想要返回的列表将会消失。

通过将带有ToList() 的LINQ 查询分配给object 变量,您可以在ForEach 中使用新创建的列表。

【讨论】:

  • 我认为你没有抓住重点。是他丢失的列表中对象的更改。
  • 没错,因为他返回的是IEnumerable,而不是在他的第一个示例中存储ToList() 调用的结果列表。
  • @Taemyr 关键在于IEnumerable 可能是IQueryable,这意味着基础数据不是可以更改的对象,而是将从每个数据库中查询的数据迭代。
  • @juharr 同意,或者选择从其他机制创建新对象。但是这个答案并没有表明这些项目是在执行选择期间创建的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-08
  • 2020-07-28
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
相关资源
最近更新 更多