在powershell脚本块中向数组添加元素将数组转换为字符串

Adding element to array in powershell scriptblock converts array to string

我注意到在脚本块中使用数组有奇怪的行为。以下代码显示了问题:

$array = @("x", "y")

Write-Host "$($array.GetType().Name)"
Write-Host "$($array.GetType().BaseType)"

$bad = {
    $array += "z"
    Write-Host "$($array.GetType().Name)"
    Write-Host "$($array.GetType().BaseType)"
    $array
}

$good = {
    $array = $array.Clone()
    $array += "z"
    Write-Host "$($array.GetType().Name)"
    Write-Host "$($array.GetType().BaseType)"
    $array
}

& $good
& $bad

执行脚本将产生以下输出:

Object[]
array
Object[]
array
x
y
z
String
System.Object
z

脚本块 $bad 没有像我预期的那样工作。它将数组转换为字符串,但它应该只是将元素 z 添加到数组中。如果没有添加元素,数组可以正常使用

我在 powershell 5.0 和 5.1 中注意到了这种行为,但在 ISE 中没有。这是一个错误还是有人可以解释一下?

这是范围问题。 scriptblocks中赋值操作左边的变量是在局部作用域中定义的。

此声明

$array = $array.Clone()

克隆 global 变量 $array 的值并将其分配给 local 变量 $array (名称相同,但由于作用域不同而变量不同)。局部变量 $array 然后包含原始数组的副本,因此下一条语句

$array += "z"

向该数组追加一个新元素。

在您的其他脚本块中,您立即将一个字符串附加到(本地)变量 $array。在这种情况下,局部变量为空,因此 $array += "z"$array = "z" 具有相同的效果,留下一个仅包含字符串 "z".

的变量

指定正确的范围,您将获得预期的行为:

$array = @("x", "y")

$not_bad = {
    $script:array += "z"
    Write-Host "$($script:array.GetType().Name)"
    Write-Host "$($script:array.GetType().BaseType)"
    $script:array
}

& $not_bad

但是请注意,这实际上会修改 global/script 范围内的原始数组(您的 $good 示例保持原始数组不变)。

我不确定我是否会将此行为视为错误,但它绝对是一个问题。

我想 post 我的首选解决方案,它基于 Ansgars 的解释:

$array = @("x", "y")

$not_bad = {
    $array = $array + "z"
    Write-Host "$($array.GetType().Name)"
    Write-Host "$($array.GetType().BaseType)"
    $array
}

& $not_bad

重要的是在添加更多元素之前分配给局部变量(或更好地创建局部变量)。一个简单的

$array = $array

可以,但这一行可能会造成混淆。