linq .Cast 或在ConvertAll中转换为列表
考虑您必须将List
类型的mylist
转换为List
,其中T
是Base
子类
这些解决方案是否相同? 哪个有更好的表现,为什么? 我应该何时更喜欢使用第一个还是第二个?
return mylist.Cast().ToList(); return mylist.ConvertAll(x => (Base)x);
也许第二种解决方案可能会更好,因为mylist是直接转换的。
在第一个解决方案中,列表转换为IEnumerable,然后转换为列表,但我不确定。
TL; DR: ConvertAll
进行1次内存分配,但在大多数情况下.Cast.ToList
多次内存分配。
大多数LINQ扩展(如.Cast
)导致延迟执行IEnumerable
,无法转换为ICollection
(无法获取结果的.Count
)。
当结果可以转换为ICollection
, .ToList
和.ToArray
可以只进行一次内存分配来复制元素,但是当它不能:
- 最初为非空源分配4个元素缓冲区数组
- 当需要更多元素的空间时,新数组的分配大小是前一个数组的两倍
- 元素从旧数组复制到新数组,旧数组稍后由垃圾收集器释放。
更新
令人惊讶的是,这种差异似乎并不像我预期的那么重要:
method elapsed ratio count Cast.ToList 00:00:14.4487329 1.3719890831991 123456789 ConvertAll 00:00:10.5312302 0.728868773261865 Cast.ToList 00:00:01.4959734 1.50233158227713 12345678 ConvertAll 00:00:00.9957678 0.665632016125407 Cast.ToList 00:00:00.1252968 2.45948743599897 1234567 ConvertAll 00:00:00.0509442 0.40658878161491 Cast.ToList 00:00:00.0082611 3.99145006839945 123456 ConvertAll 00:00:00.0020697 0.250535515380002 Cast.ToList 00:00:00.0008097 0.620558719826417 12345 ConvertAll 00:00:00.0013049 1.61145104895105 Cast.ToList 00:00:00.0001812 0.193207547169811 1234 ConvertAll 00:00:00.0009378 5.17578125 Cast.ToList 00:00:00.0001433 0.149501661129568 123 ConvertAll 00:00:00.0009587 6.68888888888889
所以, 比赛你的马 !
int c = 123; var L = Enumerable.Range(0, c).ToList(); GC.Collect(); var sw1 = Stopwatch.StartNew(); L.Cast