Powershell 数组、函数和参考

geo*_*ced 2 powershell

我知道 Powershell 数组是不可变的对象,并且像所有对象一样,通过引用函数来传递。但是我在下面的例子中不明白为什么$b没有与$a.

唯一的区别是它$b不是强类型的。这是否意味着从toTest-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
Run Code Online (Sandbox Code Playgroud)

输出:

Modified by Test-ByRefArray, world
hello, world
Modified by Test-ByRefArray, world
Run Code Online (Sandbox Code Playgroud)

Mat*_*sen 6

这里发生的情况是,类型$a满足 的类型约束$Array1- 它已经是 a [string[]],并且 PowerShell 按原样将它传递给您的函数 - 所以$Array1现在持有对与在调用站点具有引用完全相同的数组$a的引用。

$b,在另一方面,隐式类型[object[]]-并[object[]]没有满足类型约束[string[]]$Array2

PS ~> [string[]].IsAssignableFrom([object[]])
False
Run Code Online (Sandbox Code Playgroud)

由于PowerShell的希望是有帮助的,它转换数组到一个新的[string[]],所以$Array2指的是在参数绑定已经创造了这个新的数组。

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


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

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
Run Code Online (Sandbox Code Playgroud)

输出起初可能看起来有点混乱,但在这里我们可以看到 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
Run Code Online (Sandbox Code Playgroud)

在此,另一方面,我们看到的PowerShell创建新阵列(倒数第三调试语句),然后结合$ParamArray