我最近了解了List的.ConvertAll扩展程序。我今天在代码中使用它几次,将我的对象的大型列表转换为其他对象的列表。它似乎工作得很好。但是,我不确定这与仅迭代列表和转换对象相比有多快或多快。 .ConvertAll会使用任何特殊的东西来加速转换过程,还是只需要一个简单的方法来转换列表而不必设置循环?
答案 0 :(得分:8)
没有更好的方式来找出直接到源头,字面意思是:)
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs#dbcc8a668882c0db
正如你所看到的,没有特别的魔法在继续。它只是迭代列表并通过您指定的转换器函数创建一个新项。
说实话,我不知道这种方法。通过在Select
IEnumerable<T>
上使用source.Select(input => new Something(input.Name))
扩展方法,更加惯用的.NET方式就是这样做:ConvertAll
。这样做的好处有三个:
ConvertAll
很可能是前C#3.0天的残余。无论如何,这不是一个非常神秘的方法,而Select
是一个非常清晰的描述,但坚持其他人所知的可能仍然更好,IEnumerable<T>
。ConvertAll
上使用,而List<T>
仅适用于Select
的实例。如果它是一个数组,一个列表或一个字典,Select
适用于所有这些都无关紧要。IEnumerable<TOutput>
很懒。在迭代之前它不会做任何事情。这意味着它会返回ToList()
,如果您实际上不需要列表,则可以通过调用source.Select(input => new Something(input.Name)).Take(2)
来转换为列表。或者,如果您只想转换并检索一百万个项目列表中的前两个项目,您只需执行ConvertAll
。但如果您的问题纯粹是关于将整个列表转换为另一个列表的性能,那么Select
可能会更快一些,因为它不像ToList
后跟{{1}那样通用(它知道列表有一个大小,并且可以通过索引从底层数组直接访问元素)。
答案 1 :(得分:3)
使用ILSPy进行反编译:
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
if (converter == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
}
List<TOutput> list = new List<TOutput>(this._size);
for (int i = 0; i < this._size; i++)
{
list._items[i] = converter(this._items[i]);
}
list._size = this._size;
return list;
}
.ConvertAll是否使用任何特殊功能来加速转换 过程或者它只是一种简单的转换列表的方式 必须建立一个循环?
关于转化,它没有做任何特别的事情(&#34;特殊&#34;它可以做什么?)它直接修改私人_items
和_size
成员,在某些情况下,它可能简单。
与往常一样,如果解决方案可以提高您的工作效率,代码更容易阅读等,请使用它直到分析显示出令人信服的性能原因不使用它。
答案 2 :(得分:1)
这是你描述它的第二种方式 - 基本上是一种没有设置循环的简单方法。
以下是ConvertAll()
:
List<TOutput> list = new List<TOutput>(this._size);
for (int index = 0; index < this._size; ++index)
list._items[index] = converter(this._items[index]);
list._size = this._size;
return list;
TOutput
是您要转换为的任何类型,converter
是一个委托,表示将进行转换的方法。
因此它遍历您传入的List
,通过您指定的方法运行每个元素,然后返回指定类型的新List
。
答案 3 :(得分:0)
为了在场景中精确计时,您需要自己衡量。
不要指望任何奇迹 - 它必须是O(n)操作,因为每个元素都需要转换并添加到目的地列表。
考虑使用Enumerable.Select
,因为它会进行延迟评估,可以避免大型列表的第二个副本,尤其是您需要对整个项目进行任何过滤。