1

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

$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 中没有。这是一个错误还是任何人都可以解释这个?

4

2 回答 2

2

这是一个范围问题。脚本块中赋值操作左侧的变量是在本地范围内定义的。

这个说法

$array = $array.Clone()

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

$array += "z"

将一个新元素附加到该数组。

在您的其他脚本块中,您立即将一个字符串附加到 (local) variable $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

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

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

于 2018-06-15T09:48:43.757 回答
0

我想发布基于 Ansgars 解释的首选解决方案:

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

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

& $not_bad

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

$array = $array

可以,但这条线可能会令人困惑。

于 2018-06-15T11:39:24.807 回答