为什么必须使用List
为Add
分配值,但是对于数组,可以使用[]
运算符完成?
例如:
string[] y = new string[10];
y[0] = "asdf"; //fine
List<string> x = new List<string>(10);
x[0] = "asdf"; //ArgumentOutOfRangeException
两者都不应该有相同的行为吗?
答案 0 :(得分:4)
看一下List(of T)的源代码,你会看到索引属性getter / setter看起来像这样:
// Sets or Gets the element at the given index.
//
public T this[int index] {
get {
// Fllowing trick can reduce the range check by one
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
return _items[index];
}
set {
if ((uint) index >= (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException();
}
_items[index] = value;
_version++;
}
}
请注意,在List的内部数组中设置相应的项之前,它首先检查私有_size
变量以确保它在范围内。但是,_size
未设置为数组的大小。在List的各种添加/删除方法中,大小会递增/递减,因此即使您实例化初始容量为10的列表,也就是List的数组的内部容量。这是构造函数:
// Constructs a List with a given initial capacity. The list is
// initially empty, but will have room for the given number of elements
// before any reallocations are required.
//
public List(int capacity) {
if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
_items = new T[capacity];
}
除非您使用Add / Remove / AddRange / etc,否则_size
未设置(因此保持为其初始值0)。或者使用接受IEnumerable的构造函数(在这种情况下,大小因为IEnumerable中的项目数)。
如果你考虑它就有意义了。列表的概念是这样的,当容量需要改变时,您不必担心数字索引的复杂性(和丑陋)以及调整大小/复制数组的大小。在实例化List之后,内部数组的大小应该与开发人员无关。如果你想微观管理内部数组的使用方式,那么你应该创建自己的实现,或者只使用数组。
答案 1 :(得分:1)
列表的内部结构与array
不同。在array
中,您在其定义中定义了大小的项目,而具有这些对象所需的内存大小由CLR在内存中实现。
在list<T>
中,您可以定义列表中的项目的最大值。那是( 的一部分)你必须调用Add
方法在list<T>
中添加对象的原因。您可以像在构造函数上一样为列表定义初始Capacity
。如果您需要添加超过容量,列表将为您重新排列。该框架为您管理列表中有多少项目。
另一个重要的事情是,在这两种情况下,您都可以通过index
进行访问。样本:
var obj = list[1];
var obj2 = array[1];
如果您在list<T>
/ array
上没有1
索引,则在array
中,您会获得default(T)
(正在考虑T
作为您的类型),在列表中,您将获得Exception
。
答案 2 :(得分:1)
您实现阵列的方式是正确的。
创建数组时需要声明数组的大小。没有办法解决这个问题。
但是,列表的大小更灵活。您可以根据需要添加任意数量的元素,而无需声明初始大小。但是,在添加元素后,您可以通过索引号访问或编辑它们。这是一个例子。
您正在获取该异常,因为从技术上讲,在您实际向其添加值之前,列表不会填充索引。如果能清除它,请告诉我。
//You can add your elements when you instantiate it
List<string> names = new List<string>{"Alex", "Tommy", "Bob"};
//Or you can add them later
List<string> cities = new List<string>();
cities.Add("Denver");
cities.Add("New York");
//Now that they are created you can access or edit any of the elements within them.
names[2] = "Gerard";
cities[1] = "San Francisco";
答案 3 :(得分:-2)
此构造函数不会在列表中创建任何元素。它只为可以添加到此列表的项目保留内存。 您仍然必须手动将项目插入列表,然后才能以这种方式使用。
UPD: 当您处理大型集合时,这种重载可以帮助您,并且您几乎可以确定您将N个项目放入列表中。因此,您可以在创建时保留内存,并在将项添加到此列表时避免内存分配(有时可能会很慢)。