运行此代码后:
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()或来评估为true。 ToArray()进入Select()调用。
在实际代码中,这比这个简单的插图复杂得多,用于决定是否应该附加.ToList()或.ToArray()的好经验法则是什么?我最初的想法是任何可以多次迭代的引用表达式,或者在潜在迭代不明显的情况下更安全,任何引用的表达式,其结果永远不会改变。
答案 0 :(得分:16)
不幸的是,我不认为这里有一个好的“硬性和快速”规则。这很大程度上取决于您对结果的使用方式以及查询本身实际执行的操作。
我最初的想法是任何可以多次迭代的表达式,或者在潜在的迭代不明显的情况下更安全,任何结果永远不会改变的表达式。
一般情况下,如果您要多次使用查询结果,最好通过ToList()
或ToArray()
存储它。如果您的LINQ查询是“昂贵的”,则尤其如此,因为它可以防止昂贵的操作多次运行。
通常情况下,如果您只是枚举结果,那么我会将其保留为IEnumerable<T>
。如果您计划存储结果,或多次使用结果,那么将其存储在集合中可能会有所帮助。
另一个需要注意的地方是,如果您在公共API中返回结果。虽然返回IEnumerable<T>
通常很好,但根据预期的用例,您可能需要考虑使用ToList()
来阻止操作多次执行。
至于是否使用ToList()
或ToArray()
,这实际上取决于您将如何使用结果。与每个相关的成本几乎相同(如果输入不是ToList()
,ICollection<T>
实际上具有略低的执行开销。通常情况下,我更喜欢ToList()
而不是ToArray()
,除非我对数组有特定需求或期望。
答案 1 :(得分:3)
ToList
调用List<T>(IEnumerable<T>)
构造函数创建List<T>
,而ToArrary
使用内部类Buffer<T>
来增长数组。
如果源集合(IEnumerable<T>
)实现了ICollection
接口,则这两种方法使用类似的代码逻辑来复制数据。
ICollection.CopyTo(array, 0);
否则,ToList
将动态创建List<T>
。而ToArray
将元素逐个复制到新数组中。如果数组已满,则该方法将数组大小加倍以保存数据。最后,该方法根据源集合的大小返回另一个数组。