IEnumerable.ToList()的影响

时间:2015-07-11 02:02:28

标签: c#

我只是想知道在C#中.ToList()上调用IEnumerable时会发生什么。这些项目是否实际上被复制到堆上的全新重复项目,或者新列表是否只是引用堆上的原始项目?

我想知道,因为有人告诉我调用ToList很昂贵,而如果只是将现有对象分配到新列表,那就是轻量级调用。

我写过这个小提琴https://dotnetfiddle.net/s7xIc2 只是检查哈希码足以知道吗?

3 个答案:

答案 0 :(得分:8)

IEnumerable不必包含任何内容列表。它可以(并且经常会)在请求时解析每个当前项

另一方面,IList是所有项目的完整内存副本。

所以答案是......这取决于。 什么是支持你的IEnumerable?如果它的文件系统然后是,则调用.ToList可能非常昂贵。如果它已经是一个内存列表,那么不,调用.ToList不会非常昂贵。

作为一个例子,假设您创建了一个IEnumerable,每次生成并返回一个随机数.Next被调用。在这种情况下,调用IEnumerable上的.ToList永远不会返回,并最终会抛出Out Of Memory异常。

然而,IEnumerable的数据库对象具有有限的边界(通常是:)),只要所有数据都适合内存,调用.ToList就完全合适了。

答案 1 :(得分:3)

以下是ToList的一个版本:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw Error.ArgumentNull("source");
    return new List<TSource>(source);
}

它从源代码创建一个新列表,这里是构造函数:

// Constructs a List, copying the contents of the given collection. The
// size and capacity of the new list will both be equal to the size of the
// given collection.
// 
public List(IEnumerable<T> collection) {
    if (collection==null)
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
    Contract.EndContractBlock();

    ICollection<T> c = collection as ICollection<T>;
    if( c != null) {
        int count = c.Count;
        if (count == 0)
        {
            _items = _emptyArray;
        }
        else {
            _items = new T[count];
            c.CopyTo(_items, 0);
            _size = count;
        }
    }    
    else {                
        _size = 0;
        _items = _emptyArray;
        // This enumerable could be empty.  Let Add allocate a new array, if needed.
        // Note it will also go to _defaultCapacity first, not 1, then 2, etc.

        using(IEnumerator<T> en = collection.GetEnumerator()) {
            while(en.MoveNext()) {
                Add(en.Current);                                    
            }
        }
    }
}

复制项目。

代码来自:referencesource.microsoft.com

答案 2 :(得分:1)

ToList()创建一个新的List对象,该对象将包含对原始对象的引用或对象的副本struct

例如,int的列表将是完整副本。 “产品”列表仅指产品,而非完整副本。如果修改了原件,则也会修改列表中的产品。