Array.Add与+=的区别

244

我在PowerShell Arrays中发现了一些有趣的行为,特别是如果我声明一个数组:

$array = @()

当我使用$array.Add("item")方法尝试向其中添加项目时,我收到以下错误:

Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."

然而,如果我使用$array += "item"来附加项目,则该项目将被接受而没有问题,并且似乎不适用“固定大小”的限制。

为什么会出现这种情况?


3个回答

322

使用 $array.Add() 方法时,您试图将元素添加到现有数组中。数组是固定大小的集合,因此您会收到错误消息,因为无法扩展该数组。

$array += $element 创建一个新的数组,该数组包含与旧数组相同的元素+新项目,这个更大的新数组替换了$array变量中的旧数组

您可以使用+=运算符向数组添加元素。当您使用它时,Windows PowerShell实际上会创建一个带有原始数组值和添加值的新数组。例如,要将值为200的元素添加到$a变量中的数组中,请键入:

    $a += 200

来源:about_Arrays

+= 运算是一个耗费资源的操作,因此当你需要添加许多项时,应尽可能在尽可能少的操作中添加它们,例如:

$arr = 1..3    #Array
$arr += (4..5) #Combine with another array in a single write-operation

$arr.Count
5

如果不可能,考虑使用更高效的集合,比如List或者ArrayList(参见另一个答案)。


那么在这种情况下,我们应该使用 C# 列表而不是 PowerShell 数组吗? - Kellen Stuart
3
这要看情况。如果你要频繁添加和删除许多成员,那么是的,尝试使用List或者ArrayList,它们会更快。个人而言,我99%的时间都使用+=和数组,因为我通常创建一些简短的即时脚本,这些额外的几秒钟并不重要。对于需要优化和节省时间的大型脚本,其中有很多添加/删除操作,我会使用ListArrayList - Frode F.
3
由于数组大小固定,有人想知道为什么会有Add()方法? - JohnLBevan
4
因为这个类是从IList继承而来的。尝试使用命令Get-Member -InputObject @(),将会显示出该类中的Add Method int IList.Add(System.Object value) - Frode F.
2
所以他们有.Add()是因为他们实现了IList,但它不起作用是因为他们是.IsFixedSize。那么他们为什么是固定大小的??为什么IList有一个用于检查固定大小列表的属性? - TessellatingHeckler
显示剩余2条评论

166
如果你想要一个动态大小的数组,那么你应该使用列表。不仅可以获得 .Add() 功能,而且正如 @frode-f 所解释的那样,动态数组更加内存高效,也是更好的实践方式。
而且它非常容易使用。
尝试使用以下代码替换你的数组声明:
$outItems = New-Object System.Collections.Generic.List[System.Object]

添加项目很简单。

$outItems.Add(1)
$outItems.Add("hi")

如果你真的想在完成后得到一个数组,也有一个相应的函数可以使用。

$outItems.ToArray()

1
我已经尝试过这个。我使用New-Object System.Collections.Generic.List[string]创建它,但是如果我执行.GetType,则会告诉我它是一个数组。 - Preza8
1
你尝试过使用Add()函数吗?我可以确认,如果你按照上述所述创建一个通用的List对象,你将拥有一个可变的列表,可以使用Add()Remove()方法分别添加和删除项目。 - codewario
2
@Preza8: 对我来说(New-Object System.Collections.Generic.List[string]).GetType().Name产生了预期的List\1结果; 也许您将+=应用于包含列表的变量(而不是调用.Add()方法),在这种情况下,变量值确实会转换为数组(System.Object[]`)。 - mklement0
1
快捷键:$a = new-object collections.generic.list[object] - Andrew
1
这和 $arr = New-Object System.Collections.ArrayList 是一样的吗? - Ste

18

创建数组的最常见惯用语而不使用低效的+=,就像来自循环输出的这样:

$array = foreach($i in 1..10) { 
  $i
}
$array

添加到现有数组:

[collections.arraylist]$array = 1..10
$array.add(11) > $null

2
我非常喜欢这种方法。它更加简洁,而且没有失去意图/清晰度。 - Esteban
1
@js2010 不太明白这个。你怎么用这种方法向现有数组添加一个新值? - fmotion1
@Jay 我认为这种情况不太常见,但是使用ArrayList比每次都用+=复制整个数组更有效率。 - js2010

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接