为什么在 C# 中,除非您声明数组的长度或立即添加项目,否则您不能将对象添加到数组中?例如,我不能简单地这样做
foreach(object item in array)
{
array.Add(item)
}
我必须创建一个列表并在循环后将其转换为数组。
我不想知道该怎么做,我想对为什么数组是固定长度但其他集合不是(List,ListArray)有一个逻辑解释
对原文的回答(在编辑答案之前):
因为 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 类型的类型,因为它提高了可用性/功能。
数组不可调整大小,因为这就是内存的工作方式。了解内存分配在 .NET 中的确切工作方式对于 SO 答案来说有点多,如果需要,您可以在其他地方阅读有关它的所有内容,但一个方面基本上在每个平台上都是通用的:当您为某事分配了一块内存时, 之后的下一个地址可能是其他东西的一部分。
所以你不能只是扩展一块内存并希望没有任何问题,你必须测试你是否可以扩展它并有一个计划 B,当你不能 - 该计划 B 将分配一个新的块内存,将旧东西复制到其中,并释放旧块。
为了避免多次重新分配和复制,通常的做法是使新块比旧块大一倍,因此如果您添加n
项目,您只会重新分配和复制O(log n)
次数,保持将新项目添加到动态增长的摊销时间数组下降到 O(1)。如此恒定的时间,很棒 - 不是真的。与不必重新分配相比,这仍然需要更多的时间,事实上,即使是每一个add
不会导致增长的东西,也有一点开销来确保没有增长是必要的。
因此,不增长的数组更简单、更快,并且浪费更少的内存。因此,在 C#(以及许多其他语言,如 Java 和 C++)中,您可以选择:您想使用可增长的“类数组”还是不可增长的?那里有一个权衡,这些语言选择不为你做出这个决定。
因为
数组从声明时就固定了长度,您既不能添加也不能删除项目。您可以创建一个长度更大的新数组并从一个复制到另一个,但您不能动态更改数组的长度。您可能需要一个List<>
或其他一些集合类型。
迭代时不能更改任何集合(List、Dictionay、ArrayList 等),这是语言/库设计者设置的限制。允许它会涉及大量工作,并且会影响性能,这会妨碍每个foreach 循环的性能,而不仅仅是在迭代时更改集合的那些。
所以 tl; dr 你不能因为这是它的设计方式
希望这可以帮助。
您也可以走老式路线并使用 for 循环。那不知道迭代器和集合更改问题,并且您不需要那个临时列表(似乎效率很低)。
数组有固定的长度。如果您事先知道所需的大小,您仍然可以使用循环来填充它们:
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];
}
实际上,您的问题并不清楚,或者说不太合理。如果您尝试填充现有数组(具有定义的大小,但没有值),您可以执行以下操作:
var myArray = new string[5];
for(var i = 0; i < myArray.Length; i++)
{
myArray[i] = "Some value here...";
}
然而,将现有项目添加到数组本身是没有意义的。
注意:该Add()
方法存在于List
etc. 中,但它通常表示“将此元素附加到我的集合的末尾”。
数组有一个定义的长度,它不能改变,所以你不能附加到它——只能改变现有的元素。