为什么在C#中你不能将对象添加到数组中,除非你声明数组的长度或直接添加项目?例如,我不能简单地这样做
foreach(object item in array)
{
array.Add(item)
}
我必须创建一个列表并在循环后将其转换为数组。
我不想知道该怎么做,我希望对WHY数组是固定长度的逻辑探索,但其他集合不是(List,ListArray)
答案 0 :(得分:11)
回答原文(在编辑答案之前):
因为foreach循环不动态地改变它的结束条件,所以当你动态改变它正在迭代的对象时。
在你的情况下(如果可能的话)它永远不会结束,因为在每个循环中,一个项目被添加到数组中。
您可以使用普通for循环:
int orgSize = array.Count
for (var i = 0; i < orgSize; i++)
{
array.Add(array[i])
}
回答更新的问题:为什么数组是固定长度但其他集合不是(List,ListArray):
数组是固定长度的,可能是由于历史原因并保持与C / C ++的向后兼容性。这些“普通”数组没有Add,Count,也没有动态。因此,使用List / ListArray等要容易得多,尽管这会产生成本,例如某些性能,并且在所有情况下都需要更多存储,因为需要管理实例化。 但是,如果这不是问题,我更喜欢使用List / ListArray / Dictionary类型,因为改进了可用性/功能。
答案 1 :(得分:5)
数组不可调整大小,因为内存是如何工作的。了解内存分配如何在.NET中完全正常工作对于SO答案来说有点多了,如果你愿意,你可以在别处阅读所有相关内容,但是一个方面基本上是在每个平台上都是通用的:当你为某些东西分配一块内存时,之后的下一个地址可能是其他东西的一部分。
所以你不能只是扩展一块内存并且希望没有出错,你必须测试你可以扩展它并且当你不能时有一个计划B - 该计划B将分配一个新的内存块,将旧内容复制到内存中,并释放旧块。
为避免多次重新分配和复制,通常的做法是将新块的大小设置为旧块的两倍,因此如果添加n
项,则只会重新分配和复制O(log n)
次,保持amortized time for adding a new item to a dynamically-grown array down to O(1)。如此恒定的时间,伟大 - 不是真的。现在还有更多的时间,而不是你不必重新分配,事实上即使不导致增长的每一个add
都有一点开销,以确保不需要增长爱好。
因此,不增长的数组更简单,更快,浪费更少的内存。因此,在C#(以及许多其他语言,例如Java和C ++)中,您可以选择:您是否想要使用可增长的“类似数组的东西”或不可增长的东西?那里有一个权衡,这些语言选择不为你做出决定。
答案 2 :(得分:4)
因为
数组从声明时起固定长度,既不能添加也不能删除项目。您可以创建一个具有更大长度的新数组,并将其从一个复制到另一个,但不能动态更改数组的长度。您可能需要List<>
或其他一些集合类型。
在迭代它时(List,Dictionay,ArrayList等),你不能改变任何集合,这是语言/图书馆设计者所设置的限制。允许它会涉及大量工作,并且会影响性能,这会影响每个 foreach循环的性能,而不仅仅是在迭代时更改集合的性能。
所以tl; dr你不能因为这就是它的设计方式
希望这有帮助。
答案 3 :(得分:3)
您也可以使用旧式路线并使用for-loop。这不知道迭代器和集合更改问题,并且您不需要那个临时列表(看起来效率很低)。
答案 4 :(得分:2)
数组具有固定长度。如果您事先知道所需的尺寸,则可以使用循环填充它们:
var sourceArray = new string[100];
/* populate source */
var myArray = new string[sourceArray.Length];
for (var i = 0; i < sourceArray.Length; i++)
{
myArray[i] = sourceArray[i];
}
答案 5 :(得分:1)
实际上,你的问题不清楚,或者说没有意义。如果您尝试填充现有数组(具有已定义的大小但没有值),您可以执行以下操作:
var myArray = new string[5];
for(var i = 0; i < myArray.Length; i++)
{
myArray[i] = "Some value here...";
}
然而,将现有项添加到数组本身是没有意义的。
注意:Add()
等存在List
方法,但在那里,它通常意味着“将此元素附加到我的集合的末尾”。
数组具有已定义的长度,该长度无法更改,因此您无法附加到该数组 - 仅更改现有元素。