给定正确定义的变量

$test = New-Object System.Collections.ArrayList
.Add使用数组中的项目计数污染管道,而.AddRange则不污染管道。$test.Add('Single')会将计数转储到控制台。 $test.AddRange(@('Single2'))将很干净,无需额外的努力。为什么会有不同的行为?只是一个疏忽,还是我不了解某些故意行为?

鉴于.AddRange在不使用变量(已经是数组)时需要强制转换为数组,当我知道只需要添加一项时,我倾向于使用[void]$variable.Add('String'),而在向数组添加数组时,甚至倾向于使用[void]$test.AddRange($variable),即使当$variable仅包含或只能包含单个项目时。这里的[void]不是必需的,但是我想知道是否拥有它只是最佳实践,这当然取决于上面的答案。还是我在那里也想念东西?

最佳答案



因为很多年前,有人认为ArrayList应该如何表现!
Add()返回将参数插入列表的索引,这确实有用,并且很有意义。

另一方面,对于AddRange(),尚不清楚为什么应返回任何内容,如果是,则返回什么?输入参数中第一项的索引?最后?还是应该返回带有所有插入索引的可变大小数组?那太尴尬了!因此,无论谁实现ArrayList,都决定根本不返回任何内容。

在最初设计C#VB.NETArrayList中,“污染管道”这个概念实际上并不存在,如果有人在不分配变量的情况下调用.Add(),则运行时会简单地将返回值复制回调用方。



不,这完全没有必要。 AddRange()并非神奇地有一天会改变为输出任何东西。

如果您不需要知道插入索引,请改用 [System.Collections.Generic.List[psobject]] :

$list = [System.Collections.Generic.List[psobject]]::new()

# this won't return anything, no need for `[void]`
$list.Add(123)

如果您出于某种原因必须使用ArrayList,则可以通过覆盖Add()方法来使其“沉默”:

function New-SilentArrayList {
  # Create a new ArrayList
  $newList = [System.Collections.ArrayList]::new()

  # Create a new `Add()` method, then return the list
  $newAdd  = @{
    InputObject = $newList
    MemberType = 'ScriptMethod'
    Name = 'Add'
    Value = {param($obj) $this.AddRange(@($obj))}
  }
  Write-Output $(
    Add-Member @newAdd -Force -PassThru
  ) -NoEnumerate
}

现在,您的ArrayListAdd()再也不会窥视了!

PS C:\> $list = New-SilentArrayList
PS C:\> $list.Add(123)
PS C:\> $list
123

10-07 12:29