我有一个IEnumerable<T>
,我需要一份副本。任何实现IEnumerable<T>
的东西都可以。什么是最便宜的复制方式?可能.ToArray()
?
答案 0 :(得分:22)
ToArray
不一定比ToList
快。只需使用ToList
。
只要您在枚举之前不知道原始序列的元素数量,就会发现这一点,您最终会调整数组的大小并像List<T>
一样向其添加元素,因此{{1无论如何,{} {}必须做同样的事情。此外,ToArray
为您提供List<T>
,这比原始数组更好。
当然,如果你知道ToList
实例的具体类型,可以有更快的方法,但这与关键点没有密切关系。
旁注:使用数组(除非必须)可以说是微优化,应该是avoided most of the time。
答案 1 :(得分:5)
Enumerable::ToArray
和Enumerable::ToList
最终使用相同的技术从源接收元素到内部数组缓冲区,一旦达到该缓冲区的大小,它们将分配一个大小的两倍的新缓冲区,memcpy结束并继续添加元素,重复此过程,直到源上的枚举完成。最后的差异是ToArray
在内部使用Buffer<T>
实现,然后必须分配一个确切大小的Array
并在返回结果之前将元素复制到其中。另一方面,ToList
只需返回List<T>
内部可能(可能)仅部分填充的数组缓冲区。
两个实现都有一个优化,如果源IEnumerable
是ICollection
,他们将实际分配正确的缓冲区大小,以使用ICollection::Count
开始,然后使用ICollection::CopyTo
}从源头填充他们的缓冲区。
最后你会发现它们在大多数情况下的表现几乎相同,但List<T>
在技术上是一个“较重”的类,最后要坚持,而ToArray
有额外的分配+ memcpy在最后(如果源不是ICollection
)能够交回完全正确大小的数组。我通常坚持使用ToList
,除非我知道我需要将结果传递给需要数组的东西,比如说Task::WaitAll
。
答案 2 :(得分:4)
我准备建议使用.AsParallel().ToList()
的可能性如果您有TPL可供使用,但我的双核笔记本电脑上的非正式测试显示它比仅仅.ToList()
慢7倍。因此,请坚持使用Mehrdad's answer。
答案 3 :(得分:2)
第二个最便宜的方式是说new List<T>(myEnumerable).ToArray()
。最便宜的方法是使用.ToArray()
(来自LINQ),或者,如果你没有C#3.5,创建你自己的缓冲区并在加倍的同时加上它的大小,然后在最后修剪它。
答案 4 :(得分:-1)
我知道这已经很老了......
为什么你不能做这样的事情......
的IEnumerable&LT; T&GT; original = {...在此处插入代码以填充...};
的IEnumerable&LT; T&GT; copy =(来自原始选择行中的行);
我之前使用过这个方法来推迟加载副本及其元素,直到我真正需要它们为止,而且,我不会更改“原始”的基础数据类型,将其转换为List类型。