最简单的方法来复制IEnumerable <T>?

mpe*_*pen 16 c#

我有一个IEnumerable<T>,我需要它的副本.任何实现的东西IEnumerable<T>都可以.什么是最便宜的复制方式?.ToArray()也许?

Meh*_*ari 22

ToArray不一定比快ToList.只是用ToList.

关键在于,在枚举之前你不知道原始序列的元素数量,你最终会调整一个数组的大小并像添加一样添加元素List<T>,所以无论如何ToArray都必须做同样的事情List<T>.此外,ToList给你一个List<T>比原始阵列更好的东西.

当然,如果你知道IEnumerable<T>实例的具体类型,可以有更快的方法,但这与关键点没有密切关系.

旁注:使用数组(除非必须)可以说是微优化,应该在大多数情况下避免 使用.

  • 我知道这是一个老帖子,但我想指出使用`List <>`而不是数组是更糟糕的"微优化".也就是说:由于可变性问题,数组很讨厌; 但是`列表更糟糕 - 甚至大小都是可变的.它们在构造上可能稍微快一点,但在更常见的读取使用中速度较慢; 和`List <>`有更多的GC压力.因此,如果有的话,默认情况下保守程序的正确性和性能,默认选择应该是`List <>`上的数组. (4认同)

Dre*_*rsh 5

Enumerable::ToArrayEnumerable::ToList最终使用相同的技术从源接收元素到内部数组缓冲区,一旦达到该缓冲区的大小,它们将分配一个大小翻倍的新缓冲区,memcpy并继续添加元素,重复此过程直到枚举在源头上完成了.最后的差异在于ToArray,它在Buffer<T>内部使用实现,然后必须分配一个确切大小Array并在返回结果之前将元素复制到其中.另一方面,ToList只需要在其中返回List<T>带有潜在(可能)仅部分填充的数组缓冲区.

两种实现都有一个优化,如果源IEnumerable是一个,ICollection他们将实际分配正确的缓冲区大小开始使用ICollection::Count,然后ICollection::CopyTo从源使用来填充他们的缓冲区.

最后你会发现它们在大多数情况下几乎完全相同,但从List<T>技术上来说,它最后是一个"较重"的类,最后还有ToArray额外的分配+ memcpy(如果源不是ICollection)能够交回完全正确大小的阵列.我通常坚持ToList自己,除非我知道我需要将结果传递给需要数组的东西,比如说也许Task::WaitAll.


Jes*_*cer 5

我本来打算建议.AsParallel().ToList()如果您可以使用 TPL,则可以使用,但在我的双核笔记本电脑上进行的非正式测试显示它比仅 7 倍慢.ToList()。所以,坚持迈赫达德的 回答