linq .Cast或在ConvertAll内强制转换为列表 [英] linq .Cast<> or cast inside ConvertAll for a list

查看:351
本文介绍了linq .Cast或在ConvertAll内强制转换为列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到您必须将类型为List<T>mylist转换为List<Base>,其中TBase的子类

Consider you have to convert mylist of type List<T> to List<Base> where T is subclass of Base

这些解决方案是否相同?哪个表现更好,为什么? 我什么时候应该使用第一个或第二个?

Are these solutions the same? Which has better performances, and why? When should I prefer using the first or the second?

return mylist.Cast<Base>().ToList();

return mylist.ConvertAll(x => (Base)x);

第二种解决方案可能会更好,因为mylist是直接转换的.

Maybe the second solution could be better because mylist is converted directly.

在第一个解决方案中,列表被转换为IEnumerable,然后转换为列表,但我不确定.

In the first solution the list is converted to IEnumerable, then to list, but I'm not sure.

推荐答案

TL; DR:ConvertAll分配1个内存,但是.Cast.ToList在大多数情况下不止一个.

TL;DR: ConvertAll makes 1 memory allocation, but .Cast.ToList more than one in most cases.

大多数LINQ扩展(例如.Cast<T>())导致延期执行IEnumerable<T>,而该延期执行不能转换为ICollection<T>(无法获得结果的.Count).

Most LINQ extensions (like .Cast<T>()) result in a deferred execution IEnumerable<T> that can't be cast to ICollection<T> (can't get the .Count of the result).

当结果可以转换为ICollection<T>时, .ToList .ToArray 只能分配一个内存来复制元素,但是在不能分配内存时:

When the result can be cast to ICollection<T>, .ToList and .ToArray can make just one memory allocation to copy the elements, but when it can't:

  • 最初为非空源分配了4个元素的缓冲区数组
  • 当需要更多元素的空间时,将以前一个数组大小的两倍分配新数组
  • 将元素从旧数组复制到新数组,然后由垃圾回收器释放旧数组.

更新

令人惊讶的是,这种差异似乎远没有我预期的那么重要:

Surprisingly, the difference doesn't seem nowhere near as significant as I expected:

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<object>().ToList(); sw1.Stop();

GC.Collect(); var sw2 = Stopwatch.StartNew(); L.ConvertAll(i => (object)i); sw2.Stop();

MessageBox.Show($"Cast.ToList\t{sw1.Elapsed}\t{(double)sw1.ElapsedTicks / sw2.ElapsedTicks}\n" +
                $"ConvertAll \t{sw2.Elapsed}\t{(double)sw2.ElapsedTicks / sw1.ElapsedTicks}");

这篇关于linq .Cast或在ConvertAll内强制转换为列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆