17

运行此代码后:

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'评估为假,即使两个U都包装相同的T。我还没有测试过,但我认为可以通过链接.ToList()或.ToArray()来评估为真到 Select() 调用上。

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

4

2 回答 2

20

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

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

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

通常,如果您只想枚举结果,那么我会将其保留为IEnumerable<T>. 如果您计划存储结果,或多次使用结果,则将其存储在集合中可能会有所帮助。

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

至于是否使用ToList()ToArray(),这实际上取决于您将如何使用结果。与每个相关的成本几乎相同(ToList()如果输入不是,则实际上执行开销略低ICollection<T>)。通常,除非我ToList()ToArray()数组有特定的需求或愿望,否则我更喜欢。

于 2012-08-18T01:10:42.890 回答
3

ToList调用List<T>(IEnumerable<T>)构造函数来创建一个List<T>,同时ToArrary使用一个内部类Buffer<T>来增长数组。

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

ICollection.CopyTo(array, 0);  

否则,ToListList<T>动态创建。WhileToArray将元素一个一个地复制到一个新数组中。如果数组已满,则该方法将数组大小加倍以保存数据。最后,该方法根据源集合的大小返回另一个数组。

于 2012-08-18T01:12:29.143 回答