【问题标题】:When to use LINQ's .ToList() or .ToArray()何时使用 LINQ 的 .ToList() 或 .ToArray()
【发布时间】:2012-08-18 01:06:48
【问题描述】:

运行这段代码后:

var input = new List<T>( ... );
var result = input.Select( t => new U(t) );

U first1 = null;
foreach ( U u1 in result )
    if ( first1 == null )
        first1 = u1;

U first2 = null;
foreach ( U u2 in result )
    if ( first2 == null )
        first2 = u2;

然后 'first1 == first2' 评估为 false,即使两个 U 包装相同的 T。我还没有测试过它,但我认为可以通过链接 .ToList() 或 . ToArray() 到 Select() 调用上。

在实际代码中,这比这个简单的插图要复杂得多,在决定是否应该附加 .ToList() 或 .ToArray() 时,有什么好的经验法则?我最初的想法是任何可能被多次迭代的引用表达式,或者为了更安全,以防潜在的迭代不明显,任何结果永远不会改变的引用表达式。

【问题讨论】:

  • 你确定first1 == first2 是假的吗?迭代同一个集合应该每次都返回相同的对象。
  • 是的,我确定。是同一个表达式,但不是同一个集合。
  • @PeterGluck 这是错误的,因为U 使用标准引用相等。每次迭代都会重新评估序列,因此您会获得新的 U 实例。
  • 是不是每次迭代集合时都创建new U 的问题?还是那个新的U(t) != new U(t)?懒惰是有后果的。这些后果是否可取取决于用例。

标签: c# linq .net-4.5 deferred-execution


【解决方案1】:

不幸的是,我认为这里没有一个好的“硬性”规则。这在很大程度上取决于您期望如何使用结果,以及查询本身实际上在做什么。

我最初的想法是任何可能被多次迭代的表达式,或者为了安全起见,以防潜在的迭代不明显,任何结果永远不会改变的表达式。

一般来说,如果您要多次使用查询结果,最好通过ToList()ToArray() 存储它。如果您的 LINQ 查询是“昂贵的”查询,则尤其如此,因为它可以防止昂贵的操作多次运行。

通常,如果您只想列举结果,那么我会将其保留为 IEnumerable&lt;T&gt;。如果您打算存储结果,或多次使用结果,则将其存储在集合中可能会有所帮助。

另一个需要注意的地方是您是否在公共 API 中返回结果。虽然返回IEnumerable&lt;T&gt; 通常很好,但根据预期的用例,您可能需要考虑使用ToList() 来防止操作被多次执行。

至于使用ToList()还是ToArray(),这真的取决于你将如何使用结果。与每个相关的成本几乎相同(如果输入不是ICollection&lt;T&gt;ToList() 实际上具有稍低的执行开销)。通常,我更喜欢 ToList() 而不是 ToArray(),除非我对数组有特定的需求或愿望。

【讨论】:

  • 关于公共返回值的要点。我以前遇到过这种情况。
  • 当你将结果传递给另一个方法时,同样的预防措施也适用。
【解决方案2】:

ToList 调用List&lt;T&gt;(IEnumerable&lt;T&gt;) 构造函数来创建List&lt;T&gt;,而ToArrary 使用内部类Buffer&lt;T&gt; 来增长数组。

如果源集合(IEnumerable&lt;T&gt;)实现了ICollection接口,这两种方法使用相似的代码逻辑来复制数据。

ICollection.CopyTo(array, 0);  

否则,ToList 将动态创建List&lt;T&gt;。而ToArray 将元素一一复制到一个新数组中。如果数组已满,则该方法将数组大小加倍以保存数据。最后,该方法根据源集合的大小返回另一个数组。

【讨论】:

  • 仅供参考 - ToList() 和 ToArray() 使用几乎相同的构造机制(数组大小加倍等)。主要区别在于 ToArray 可能更昂贵,因为它通常在最后需要一个额外的数组副本,因为它必须使输出大小与容量相匹配。
  • @HappyNomad FYI - 你的问题标题暗示了这个答案 - 但问题文本没有(因此我试图在我的答案中包含这两个选项)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-19
  • 2020-07-21
  • 1970-01-01
相关资源
最近更新 更多