Sel*_*enç 8 .net c# arrays generics
这是我今天看到的一个奇怪的情况:
我有一个通用列表,我希望添加项目到我的列表与它的索引器像这样:
List<string> myList = new List<string>(10);
myList[0] = "bla bla bla...";
Run Code Online (Sandbox Code Playgroud)
当我尝试这个时,我得到了 ArgumentOutOfRangeException

然后我看了List<T>索引器集方法,这里是:
[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;
}
Run Code Online (Sandbox Code Playgroud)
还看了一下Add方法:
[__DynamicallyInvokable]
public void Add(T item)
{
if (this._size == this._items.Length)
this.EnsureCapacity(this._size + 1);
this._items[this._size++] = item;
++this._version;
}
Run Code Online (Sandbox Code Playgroud)
现在,我看到两种方法都使用相同的方式:
// Add() Method
this._items[this._size++] = item;
// Setter method
this._items[index] = value;
Run Code Online (Sandbox Code Playgroud)
这_items是一个类型的数组T:
private T[] _items;
Run Code Online (Sandbox Code Playgroud)
并在构造函数_items初始化如下:
this._items = new T[capacity]
Run Code Online (Sandbox Code Playgroud)
现在,在所有这些之后,我很好奇为什么我不能用索引将项目添加到我的列表中
,尽管我明确指定了列表容量?
ang*_*son 16
原因是您没有使用索引器添加到列表中,而是替换现有项目.
由于您尚未向列表中添加任何项目,因此它是空的,并且任何尝试使用索引器向其"添加"项目都会抛出该异常.
这个:
new List<string>(11);
Run Code Online (Sandbox Code Playgroud)
不创建包含11个元素的列表,它最初创建一个容量为11个元素的列表.这是一个优化.如果添加更多元素,则必须在内部调整列表大小,并且可以传递预期或已知容量以避免过多的调整大小.
这是一个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
}
Run Code Online (Sandbox Code Playgroud)
输出:

内幕
在内部,在a中List<T>,数组实际上用于保存元素.此外,Count保留属性/值以跟踪实际使用了多少个数组元素.
构造空列表而不传入容量时,将使用默认值,这是该数组的初始大小.
当你不断向列表中添加新元素时,慢慢地你将填充该数组,直到最后.一旦填充了整个数组,并向其添加了另一个元素,就必须构造一个更大的新数组.然后将旧数组中的所有元素复制到这个新的更大的数组中,从现在开始,使用该数组.
这就是内部代码调用该EnsureCapacity方法的原因.如有必要,此方法是执行调整大小操作的方法.
每次必须调整数组大小时,都会构造一个新数组并复制所有元素.随着阵列的增长,这种操作会增加成本.这不是所有的那么多,但它仍然是不自由的.
这就是为什么,如果你知道你需要在列表中存储1000个元素,那么最好先传入一个容量值.这样,该数组的初始大小可能足够大,永远不需要调整大小/替换.同时,传递一个非常大的容量值并不是一个好主意,因为这可能最终会占用大量内存.
还要知道答案的这一部分中的所有内容都没有记录(据我所知)行为,如果您从中学到的任何细节或特定行为都不应该影响您编写的代码,除了传递一个好的知识容量值.
不,这并不奇怪.您错误地假设接受容量的构造函数初始化列表中的许多元素.它不是.列表为空,您必须添加元素.
如果由于某种原因你需要用元素初始化它,你可以这样做:
new List<string>(Enumerable.Repeat<string>(string.Empty, 11));
Run Code Online (Sandbox Code Playgroud)
听起来像string[]阵列更合适.
奇怪与否.它记录在案:http://msdn.microsoft.com/en-us/library/0ebtbkkc(v = vs.110).aspx
Exception: ArgumentOutOfRangeException
index is less than 0.
-or-
index is equal to or greater than Count.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1806 次 |
| 最近记录: |