int count = 50;
List<float> myList = new List<float>(50);
output[0] = 0.0f;
但是我遇到了错误:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
显然我误解了List(或者可能是任何其他集合?)的初始容量。请问有人能够解释一下初始容量的作用吗?
.Add
: (链接)
Method A: Dictionary, no capacity
Time: 1350 ms
Method B: Dictionary, has capacity
Time: 700 ms
Method C: Dictionary, const capacity
Time: 760 ms
Method D: Dictionary, over-large capacity
Time: 1005 ms
Method E: List, no capacity
Time: 1010 ms
Method F: List, accurate capacity
Time: 575 ms
因此,当您添加100个元素时,预分配似乎可以将所需时间减少一半。虽然我不喜欢过早优化,但如果您知道列表的大小,向CLR提供提示确实值得一试。
首先,为什么会出现异常:
通过定义初始容量,您只是指定了列表在需要调整大小之前可以存储的元素数量。
这并不意味着您在列表中有可访问的索引。您的列表仍然为空,因此当您执行以下操作时:
myList[0] = 0.0f;
您遇到了异常,但如果按照以下步骤操作:
List<float> myList = new List<float>(50);
myList.Add(0);
myList[0] = 2.0f;
现在,您不会因为索引0
处存在一个元素而收到异常。
现在回答您问题的第二部分,“Capacity”实际上是什么意思:
请参见:List<T>.Capacity
属性:
容量是List在需要调整大小之前可以存储的元素数量,而计数是实际上在List中的元素数量。
容量始终大于或等于计数。如果在添加元素时计数超过了容量,则通过自动重新分配内部数组来增加容量,然后复制旧元素并添加新元素。
分配新数组,然后将项目从旧数组移动到新数组的操作是昂贵的(性能方面)。
因此,如果您从一开始就知道要向列表中添加多少项。则可以使用具有所需初始容量的基础数组创建列表。它用于预分配列表所使用的内部数组。(此内部数组的大小由List.Capacity
确定。)
然而,仅仅因为该内部数组的大小是固定的,并不意味着列表的元素就可用;在你(例如)使用List.Add()
添加适当的元素之前,它们并不可用。列表当前可寻址的大小由List.Count
指定。
当你向列表中添加新元素时,它首先检查内部数组是否有足够的空间,如果有,则增加一个内部计数器,并使用内部数组的一个位置。
如果没有足够的空间,它会分配一个新的缓冲区,大小是旧缓冲区的两倍,将所有元素从旧缓冲区复制到新缓冲区,然后丢弃旧缓冲区。然后它可以使用新缓冲区的一个位置。这显然是一个非常昂贵的操作。
通过设置初始大小,您可以避免一些(或全部)缓冲区重新分配。
一个常见的用法是当您知道列表的最大可能大小,但不知道最小大小,并且希望在进行尽可能少的重新分配的同时填充列表。
List<T>.Capacity
的内容。 - Habib