3

为什么在 C# 中,除非您声明数组的长度或立即添加项目,否则您不能将对象添加到数组中?例如,我不能简单地这样做

foreach(object item in array)
{
   array.Add(item)
}

我必须创建一个列表并在循环后将其转换为数组。

我不想知道该怎么做,我想对为什么数组是固定长度但其他集合不是(List,ListArray)有一个逻辑解释

4

6 回答 6

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 类型的类型,因为它提高了可用性/功能。

于 2013-07-09T10:24:31.460 回答
5

数组不可调整大小,因为这就是内存的工作方式。了解内存分配在 .NET 中的确切工作方式对于 SO 答案来说有点多,如果需要,您可以在其他地方阅读有关它的所有内容,但一个方面基本上在每个平台上都是通用的:当您为某事分配了一块内存时, 之后的下一个地址可能是其他东西的一部分。

所以你不能只是扩展一块内存并希望没有任何问题,你必须测试你是否可以扩展它并有一个计划 B,当你不能 - 该计划 B 将分配一个新的块内存,将旧东西复制到其中,并释放旧块。

为了避免多次重新分配和复制,通常的做法是使新块比旧块大一倍,因此如果您添加n项目,您只会重新分配和复制O(log n)次数,保持将新项目添加到动态增长的摊销时间数组下降到 O(1)。如此恒定的时间,很棒 - 不是真的。与不必重新分配相比,这仍然需要更多的时间,事实上,即使是每一个add不会导致增长的东西,也有一点开销来确保没有增长是必要的。

因此,不增长的数组更简单、更快,并且浪费更少的内存。因此,在 C#(以及许多其他语言,如 Java 和 C++)中,您可以选择:您想使用可增长的“类数组”还是不可增长的?那里有一个权衡,这些语言选择不为你做出这个决定。

于 2013-07-09T11:08:06.113 回答
4

因为

  1. 数组从声明时就固定了长度,您既不能添加也不能删除项目。您可以创建一个长度更大的新数组并从一个复制到另一个,但您不能动态更改数组的长度。您可能需要一个List<>或其他一些集合类型。

  2. 迭代时不能更改任何集合(List、Dictionay、ArrayList 等),这是语言/库设计者设置的限制。允许它会涉及大量工作,并且会影响性​​能,这会妨碍每个foreach 循环的性能,而不仅仅是在迭代时更改集合的那些。

所以 tl; dr 你不能因为这是它的设计方式

希望这可以帮助。

于 2013-07-09T10:44:07.313 回答
3

您也可以走老式路线并使用 for 循环。那不知道迭代器和集合更改问题,并且您不需要那个临时列表(似乎效率很低)。

于 2013-07-09T10:27:06.707 回答
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]; 
}
于 2013-07-09T10:47:31.800 回答
1

实际上,您的问题并不清楚,或者说不太合理。如果您尝试填充现有数组(具有定义的大小,但没有值),您可以执行以下操作:

var myArray = new string[5];

for(var i = 0; i < myArray.Length; i++)
{
  myArray[i] = "Some value here..."; 
}

然而,将现有项目添加到数组本身是没有意义的。

注意:该Add()方法存在于Listetc. 中,但它通常表示“将此元素附加到我的集合的末尾”。

数组有一个定义的长度,它不能改变,所以你不能附加到它——只能改变现有的元素。

于 2013-07-09T10:42:50.383 回答