问题描述
下面是一个奇怪的情况,我今天看到:
Here is a strange situation I have seen today:
我有一个通用的清单,我想添加项目到我的清单与它的索引是这样的:
I have a generic list and I want add items to my list with it's indexer like this:
List<string> myList = new List<string>(10);
myList[0] = "bla bla bla...";
当我尝试这一点,我越来越 ArgumentOutOfRangeException
When I try this, I'm getting ArgumentOutOfRangeException
然后我看了看名单,其中,T&GT;
索引集的方法,在这里它是:
Then I looked at List<T>
indexer set method, and here it is:
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]
set
{
if ((uint) index >= (uint) this._size)
ThrowHelper.ThrowArgumentOutOfRangeException(); //here is exception
this._items[index] = value;
++this._version;
}
和也看了添加
方法:
[__DynamicallyInvokable]
public void Add(T item)
{
if (this._size == this._items.Length)
this.EnsureCapacity(this._size + 1);
this._items[this._size++] = item;
++this._version;
}
现在,当我看到这两种方法都使用相同的方式:
Now, as I see both methods are using the same way:
// Add() Method
this._items[this._size++] = item;
// Setter method
this._items[index] = value;
在 _items
是一个类型的数组 T
:
The _items
is an array of type T
:
private T[] _items;
和在构造 _items
这样的初始化:
And in the constructor _items
initialized like this:
this._items = new T[capacity]
现在,毕竟这些我很好奇,为什么我不能添加项目到我的列表索引
虽然我明确指定列表的能力?
Now, after all of these I'm curious about why I can't add items into my list with an index
,although I specify list capacity explicitly?
推荐答案
原因是,你不这样做的添加的到列表中的索引,你的替换现有项目。
The reason is that you don't add to the list with the indexer, you replace existing items.
由于您没有添加任何产品列表,它是空的,并且在使用索引加项目,将抛出该异常任何企图。
Since you have not yet added any items to the list, it is empty, and any attempt at using the indexer to "add" items to it will throw that exception.
本:
new List<string>(11);
不创建包含11个元素的列表,它会创建与11个元素最初容量的列表。这是一个优化。如果您添加更多的元素,名单将在内部调整大小,你可以通过在预期的或已知的能力,以避免过多的尺寸缩小了。
does not create a list with 11 elements, it creates a list with capacity for 11 elements initially. This is an optimization. If you add more elements, the list will have to be resized internally, and you can pass in the expected or known capacity to avoid too many of those resizes.
下面是一个 LINQPad 计划演示:
void Main()
{
var l = new List<string>(10);
l.Dump(); // empty list
l.Add("Item");
l.Dump(); // one item
l[0] = "Other item";
l.Dump(); // still one item
l.Capacity.Dump(); // should be 10
l.AddRange(Enumerable.Range(1, 20).Select(idx => idx.ToString()));
l.Capacity.Dump(); // should be 21 or more
}
输出:
内幕
在内部,在名单,其中,T&GT;
,数组实际上是用来抱的元素。此外,计数
属性/值保持跟踪如何将这些数组元素的许多实际上已经使用。
Internally, inside a List<T>
, an array is actually used to hold the elements. Additionally, a Count
property/value is kept to keep track of how many of those array elements have actually been used.
当你构建一个空的列表,而不是传递一个能力,一个默认的被使用,这是该数组的初始大小。
When you construct an empty list, not passing in a capacity, a default one is used, and this is the initial size of that array.
当你不断加入新的元素到列表中,慢慢的你将填补这个数组,接近尾声。一旦你已经充斥了整个阵列,并添加其他元素,它,一个新的,更大的,阵列将被修建。所有在旧数组中的元素,然后复制到这种新的,更大的,阵列,以及从现在开始,该阵列被用来代替
As you keep adding new elements to the list, slowly you will fill up that array, towards the end. Once you have filled the entire array, and add another element to it, a new, bigger, array will have to be constructed. All the elements in the old array are then copied over to this new, bigger, array, and from now on, that array is used instead.
这就是为什么内部code调用 EnsureCapacity
方法。此方法是一个做大小调整操作中,如果有必要的。
That is why the internal code calls that EnsureCapacity
method. This method is the one doing the resize operation, if necessary.
每次阵列具有被调整,新阵列被构造和所有元素复制。作为数组的增长,这种操作生长在成本。这不是的所有的那么多,但它仍然是不自由的。
Every time the array has to be resized, a new array is constructed and all the elements copied over. As the array grows, this operation grows in cost. It's not all that much, but it still isn't free.
这就是为什么,如果你知道你将需要存储,可以说,在列表中1000个元素,它是通过在一个容量值开始与一个不错的主意。这样一来,该数组的初始大小可能会足够大,从来没有需要调整大小/更换。与此同时,这不是一个好主意,只是传递的容量非常大的值,因为这可能最终会使用大量的内存不必要的。
That is why, if you know that you will need to store, say, 1000 elements in the list, it is a good idea to pass in a capacity value to begin with. That way, the initial size of that array might be large enough to never need to be resized/replaced. At the same time, it's not a good idea to just pass in a very large value for capacity, as this might end up using a lot of memory unnecessary.
也知道,一切都在这一部分的回答是未公开的(据我所知)的行为,并应任何细节或具体的行为,你可能会从中学到不应该影响到c您写的$ C $,比其他知识传递一个良好的容量值。
Also know that everything in this section of the answer is undocumented (as far as I know) behavior, and should any details or specific behavior you might learn from it should never influence the code you write, other than the knowledge about passing in a good capacity value.
这篇关于为什么我不能用索引项目添加到泛型列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!