C#List .ConvertAll效率和开销

时间:2014-05-03 00:59:55

标签: c# performance list convertall

我最近了解了List的.ConvertAll扩展程序。我今天在代码中使用它几次,将我的对象的大型列表转换为其他对象的列表。它似乎工作得很好。但是,我不确定这与仅迭代列表和转换对象相比有多快或多快。 .ConvertAll会使用任何特殊的东西来加速转换过程,还是只需要一个简单的方法来转换列表而不必设置循环?

4 个答案:

答案 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;
}
  1. 创建新列表。
  2. 通过迭代当前实例来填充新列表,执行指定的委托。
  3. 返回新列表。
  4.   

    .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,因为它会进行延迟评估,可以避免大型列表的第二个副本,尤其是您需要对整个项目进行任何过滤。