我注意到在scriptblocks中使用数组的奇怪行为。以下代码显示了问题:
$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中却没有。这是一个错误还是任何人都可以解释这个?
答案 0 :(得分:1)
这是一个范围问题。 scriptblocks中赋值操作左侧的变量在本地范围内定义。
本声明
$array = $array.Clone()
克隆全局变量$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
但请注意,这实际上会修改全局/脚本范围中的原始数组(您的$good
示例保持原始数组不变)。
我不确定我是否会将此行为视为错误,但这绝对是一个问题。
答案 1 :(得分: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
会这样做,但这一行可能会令人困惑。