【问题标题】:Does List<T>.ToList() enumerate the collectionList<T>.ToList() 是否枚举集合
【发布时间】:2014-01-27 13:39:13
【问题描述】:

在 StackOverflow 中,ICollection(或派生自 ICollection&lt;T&gt; 的类)的 ToList() 扩展方法有很多用法。

我已经拿出了很好的反编译器来看看ToList()扩展方法是如何执行的,它是否随时枚举集合。通过我遇到的来源:

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

现在这很简单,所以ToList() 扩展方法只是用源对象创建一个新的List&lt;T&gt;。深入挖掘 List 构造函数会显示这一行。

ICollection<T> ts = collection as ICollection<T>;
//.. ommited code
ts.CopyTo(this._items, 0);

如您所愿,您将深入研究CopyTo 方法。这就是我卡住的地方。在对方法调用进行了所有挖掘之后,我们得到了最终的 extern 方法调用

[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecurityCritical]
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable);

我的问题是(虽然我似乎找不到)ToList() 扩展方法 (ICollection&lt;T&gt;.CopyTo()) 在执行时会遍历集合(数组)的所有对象吗?

子问题:在哪里可以找到上述extern void Copy() 的来源?

编辑:我已经直接编辑了这个问题,因为我意识到我正在尝试获取接口规范而不是实现。对不起

【问题讨论】:

  • 我想我可能需要重新表述这个问题,因为它应该专门讨论 ToList() 函数..
  • 我已经稍微更新了我的答案来说明这一点,因为你打电话给ToList() 真的很重要。

标签: c# icollection


【解决方案1】:

我的问题是(虽然我似乎找不到)ToList() 扩展方法(ICollection&lt;T&gt;.CopyTo())遍历所有 集合的对象 (Array) 何时执行?

不,它没有。它只是使用Array.Copy复制底层数组存储。


更新

只是为了确保我的答案被正确解释。 ToList() 在另一个 List&lt;T&gt;T[] 数组(或其他实现 ICollection.CopyTo 的不带枚举器的集合)上直接调用时不会枚举源集合。

当您致电ToList&lt;&gt; 时,例如在Enumerable.Range(0, 1000).ToList() 上会有一个枚举。当您使用任何 LINQ 方法时,也会执行枚举,例如myList.Select(x =&gt; x.PropertyName).ToList() 会引起枚举。

更新结束


void ICollection.CopyTo(Array array, int arrayIndex)
{
    if (array != null && array.Rank != 1)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
    }
    try
    {
        Array.Copy(this._items, 0, array, arrayIndex, this._size);
    }
    catch (ArrayTypeMismatchException)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType);
    }
}

它使用非托管 c++ 代码以有效的方式做到这一点:

此方法等价于标准C/C++函数memmove,而不是memcpy.

来自Array.Copy Method (Array, Array, Int32)

【讨论】:

  • +1 C/C++ 函数 memmove,而不是 memcpy。 Array.Copy 方法(数组,数组,Int32)
  • 我知道块复制会比枚举更有效,但它仍然不是 O(n) 操作吗?它肯定必须是值类型的集合(例如List&lt;int&gt;().ToList()),不是吗?因为必须复制每个值。但即使对于引用类型,memmove 也必须是 O(n) 对吧?
【解决方案2】:

ToList() 扩展方法 (ICollection.CopyTo()) 是否遍历 Collection 的所有对象

这取决于ICollection&lt;T&gt; 在特定类中的实现方式。

例如,List&lt;T&gt; 实现只是复制数组(没有迭代),因为内部List&lt;T&gt; 使用数组作为存储。但没有什么能阻止您(或其他人)编写实现,它将遍历源集合。

在哪里可以找到上面的 extern void Copy() 的源代码

MethodImpl(MethodImplOptions.InternalCall) 标记的方法在非托管C++ 代码中实现。我不确定它们是否有任何开源资源。但我想,最终会有像memcpy(...) 这样的东西。

【讨论】:

    【解决方案3】:

    extern 表示该函数将在 C# 代码之外实现。它可以用 C/C++ 实现。更多细节:

    extern keyword

    【讨论】:

    • 我理解关键字extern 的含义,我很想知道在哪里可以找到源文件。我似乎也找不到从哪个外部代码加载。
    • 哦,我明白了,让我们来看看这个人@Hans Passant。不知道怎么请他回答你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    相关资源
    最近更新 更多