Powershell 数组、函数和引用

标签 powershell

我了解 Powershell 数组是不可变对象(immutable对象),并且像所有对象一样,通过引用传递给函数。但是在下面的示例中我不明白的是为什么 $b$a 的值不同。

唯一的区别是 $b 不是强类型的。这是否意味着 Test-ByRefArray$b[object[]] 转换为 [string[]] ,实际上创建了一个新对象,这可以解释为什么 Test-ByRefArray 对此新对象所做的更改对原始对象没有影响?

function Test-ByRefArray {
    param (
        [string[]] $Array1,
        [string[]] $Array2
    )
    $Array1[0] = "Modified by Test-ByRefArray"
    $Array2[0] = "Modified by Test-ByRefArray"
}

function Test-Array {
    [string[]] $a = 'hello', 'world'
    $b = 'hello', 'world'
    $c = $a #by ref: if a is updated, so is $c

    Test-ByRefArray -Array1 $a -Array2 $b

    $a -join ", "
    $b -join ", "
    $c -join ", "
}

Test-Array

输出:

Modified by Test-ByRefArray, world
hello, world
Modified by Test-ByRefArray, world

最佳答案

这里发生的是 $a 的类型满足 $Array1 的类型约束 - 它已经 [string []],PowerShell 按原样将其传递给您的函数 - 因此 $Array1 现在拥有对 $ 完全相同 数组的引用a 在调用站点有对的引用。

另一方面,

$b 是隐式类型的 [object[]] - 而 [object[]]满足 $Array2 上的类型约束 [string[]]:

PS ~> [string[]].IsAssignableFrom([object[]])
False

由于 PowerShell 想要提供帮助,它数组转换为新的 [string[]],因此 $Array2 指的是这个在参数绑定(bind)期间创建的新数组。

因此,$b 引用的数组的内容永远不会被修改 - $Array2 引用一个完全不同的数组。


我们可以观察 Trace-Command 的输出中是否发生类型转换(或类型强制) ,在 Windows PowerShell 5.1 中:

PS ~> Trace-Command -Expression {&{param([string[]]$ParamArray)} @([string[]]@())} -Name ParameterBinding -PSHost
DEBUG: ParameterBinding Information: 0 : BIND arg [System.String[]] to parameter [ParamArray]
DEBUG: ParameterBinding Information: 0 :     Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :         result returned from DATA GENERATION: System.String[]
DEBUG: ParameterBinding Information: 0 :     BIND arg [System.String[]] to param [ParamArray] SUCCESSFUL

起初输出可能看起来有点困惑,但在这里我们可以看到 PowerShell 使用 $ParamArray 参数的类型约束并确定输入参数已经是 [string []] - 无需实际工作。

现在让我们传递一个隐式类型数组:

PS ~> Trace-Command -Expression {&{param([string[]]$ParamArray)} @(@())} -Name ParameterBinding -PSHost
DEBUG: ParameterBinding Information: 0 : BIND arg [System.Object[]] to parameter [ParamArray]
DEBUG: ParameterBinding Information: 0 :     Executing DATA GENERATION metadata: [System.Management.Automation.ArgumentTypeConverterAttribute]
DEBUG: ParameterBinding Information: 0 :         result returned from DATA GENERATION: System.Object[]
DEBUG: ParameterBinding Information: 0 :     Binding collection parameter ParamArray: argument type [Object[]], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType
DEBUG: ParameterBinding Information: 0 :     Arg is IList with 0 elements
DEBUG: ParameterBinding Information: 0 :     Creating array with element type [System.String] and 0 elements
DEBUG: ParameterBinding Information: 0 :     Argument type System.Object[] is IList
DEBUG: ParameterBinding Information: 0 :     BIND arg [System.String[]] to param [ParamArray] SUCCESSFUL

在这里,另一方面,我们看到 PowerShell 创建一个新数组(倒数第三个调试语句),然后将 that 绑定(bind)到 $ParamArray

关于Powershell 数组、函数和引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68186415/

相关文章:

sql-server - 在Powershell中查询SqlServer

.net - 如何在powershell中为文件列表设置颜色

sql-server - Invoke-Sqlcmd 运行脚本两次

powershell - 将输入变量从批处理文件发送到 powershell 脚本

session - Powershell脚本杀死.exe终端服务器断开的 session

Azure DevOps Powershell 脚本无法创建 SSL/TLS 安全通道

events - 在PowerShell中,如何为COM对象实现事件处理程序?

powershell - 每个循环无法处理所有字符串

Powershell:基于局部变量的条件标志

azure - 有谁知道如何使用 Powershell 从 AzureAD 中提取动态组成员资格规则?