我最近了解了 List 的 .ConvertAll 扩展。我今天在工作中在代码中使用了几次,将我的大量对象列表转换为其他对象的列表。它似乎工作得很好。但是,我不确定这与仅迭代列表和转换对象相比有多有效或多快。.ConvertAll 是否使用任何特殊的东西来加快转换过程,或者它只是一种无需设置循环即可转换列表的简便方法?
4 回答
从字面上看,没有比直接访问源更好的方法了:)
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs#dbcc8a668882c0db
正如你所看到的,没有什么特别的魔法发生。它只是遍历列表并通过您指定的转换器函数创建一个新项目。
老实说,我不知道这种方法。进行这种投影的更惯用的 .NET 方法是通过使用Select
扩展方法,IEnumerable<T>
如下所示:source.Select(input => new Something(input.Name))
. 这样做的好处有三个:
- 正如我所说的,它更符合规范,
ConvertAll
很可能是 C#3.0 之前的遗留物。无论如何,这不是一个非常神秘的方法,并且ConvertAll
是一个非常清晰的描述,但坚持其他人知道的内容可能会更好,即Select
. - 它适用于所有
IEnumerable<T>
,而ConvertAll
仅适用于List<T>
. 无论是数组、列表还是字典,Select
都可以使用它们。 Select
是懒惰的。在您对其进行迭代之前,它不会做任何事情。这意味着它返回一个然后如果您实际上不需要IEnumerable<TOutput>
列表,您可以通过调用或不调用将其转换为列表。或者,如果您只想转换和检索一百万项列表中的前两项,您可以简单地执行.ToList()
source.Select(input => new Something(input.Name)).Take(2)
但是,如果您的问题纯粹是关于将整个列表转换为另一个列表的性能,那么ConvertAll
可能会更快一些,因为它比 aSelect
后跟 a更通用ToList
(它知道列表具有大小并且可以通过索引直接访问元素例如,来自底层数组)。
使用 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 是否使用任何特殊的东西来加快转换过程,或者它只是一种无需设置循环即可转换列表的简便方法?
它在转换方面没有做任何特别的事情(它可以做什么“特别”的事情?)它直接修改私有_items
和成员,所以在某些情况下_size
它可能会更快。
像往常一样,如果该解决方案使您更有效率,代码更易于阅读等,请使用它,直到分析显示一个令人信服的性能理由不使用它。
这是您描述它的第二种方式-基本上是一种不设置循环的速记方式。
这是胆量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
指定类型的新元素。
为了在您的场景中精确计时,您需要自己衡量。
不要期待任何奇迹 - 它必须是 O(n) 操作,因为每个元素都需要转换并添加到目标列表中。
考虑Enumerable.Select
改用它,因为它会进行惰性评估,这可能会避免大列表的第二个副本,尤其是您需要在此过程中对项目进行任何过滤。