我正在学习C#并基本知道数组与List
之间的区别,即最后一个是通用的并且可以动态增长,但我想知道:
List
元素顺序位于堆像数组中,还是每个元素“随机”位于不同的位置?List
更快?答案 0 :(得分:6)
让我们先看看第二个和第三个问题:
如果这样做会影响访问速度&从内存中检索数据?
如果这是真的是什么使得数组比列表快一点?
.NET中只有一种类型的“本机”集合(使用.NET我的意思是CLR,所以是运行时):数组(从技术上讲,如果你认为string
是一种集合,然后有两种原生类型的集合:-))(从技术上讲,第2部分:并非所有你认为是数组的数组都是“本机”数组......只有基于单维0的数组才是“本机”数组。类型为{的数组{1}}不是,并且第一个元素没有索引0的数组不是。每个其他集合(T[,]
除外)都是在它上面构建的。如果您使用LinkedList<>
查看List<T>
,您会看到IlSpy
T[]
已添加int
Count
T[].Length
是Capacity
)。显然,一个数组比List<T>
快一点,因为要使用它,你只需要少一个间接(你可以直接访问数组,而不是访问访问列表的数组)。
让我们看看第一个问题:
List元素是按顺序排列在堆类数组中还是每个元素随机位于不同的位置?
在内部基于数组,显然List<>
会像数组一样记忆其元素,因此在连续的内存块中(但要注意List<SomeObject>
SomeObject
是Dictionary<>
一个引用类型,列表是引用的列表,而不是对象的列表,因此引用被放在一个连续的内存块中(我们将忽略它与高级内存对计算机的管理,“连续的内存块”这个词并不完全“,最好说”一个连续的地址块“))
(是的,甚至HashSet<>
和LinkedList
都是在数组上构建的。相反,可以在不使用数组的情况下构建类似树的集合,因为它更类似于CIL
)< / p>
一些额外的细节:Newarr
语言(编译的.NET程序中使用的中间语言)有四组与“本机”数组一起使用的指令:
Ldelem
Ldelem_*
和家人Stelem
Stelem_*
和家人ReadOnly
OpCodes.Newarr
(不要问我使用它,我不知道,文档也不清楚)
如果查看// Summary:
// Pushes an object reference to a new zero-based, one-dimensional array whose
// elements are of a specific type onto the evaluation stack.
,您会在XML文档中看到此评论:
{{1}}
答案 1 :(得分:4)
是的,列表中的元素是连续存储的,就像数组一样。 List实际上在内部使用数组,但这是一个您不应该真正需要关注的实现细节。
当然,为了从该声明中获得正确的印象,您还必须了解.NET中的内存管理。即,the difference between value types and reference types,以及如何存储这些类型的对象。值类型将存储在连续的内存中。对于引用类型,引用将存储在连续的内存中,但不存储在实例本身中。
使用List的优点是类内部的逻辑处理为您分配和管理项目。您可以在任何地方添加元素,从任何地方删除元素,并增加集合的整个大小,而无需进行任何额外的工作。当然,这也是使List比数组略慢的原因。如果为了符合您的请求而必须进行任何重新分配,那么当分配一个新的,更大的数组并将元素复制到它时,将会有性能损失。但是,如果您编写代码以使用原始数组手动执行它,它将不会慢。
如果您的长度要求是固定的(即,您永远不需要增加/扩展阵列的总容量),您可以继续使用原始阵列。它甚至可能比List略快,因为它避免了额外的开销和间接(尽管这可能会被JIT编译器优化)。
如果您需要能够动态调整集合的大小,或者您需要List类提供的任何其他功能,只需使用List。性能差异几乎难以察觉。