I am currently using anonymous functions in Powershell and I noticed there is a weird casting problem when going from System.ValueType to System.Object.
Take the following example:
$f = {
param($InputArray)
Write-Host "`$Arr Type During Call:" ($InputArray.GetType().FullName)
Write-Host "`$Arr Contents During Call:" $InputArray
}
[object[]]$Arr = [object[]]@($true, $false)
Write-Host "`$Arr Type Before Call:" ($Arr.GetType().FullName)
Write-Host "`$Arr Contents Before Call:" $Arr "`n"
$f.Invoke($Arr)
The following example will output the following:
$Arr Type Before Call: System.Object[]
$Arr Contents Before Call: True False$Arr Type During Call: System.Boolean
$Arr Contents During Call: True
It looks like Powershell casted my variable $Arr
into the type System.Boolean
. If I force the parameter to be of type object[]
, a new problem is introduced:
$f = {
param([object[]]$InputArray)
Write-Host "`$Arr Type During Call:" ($InputArray.GetType().FullName)
Write-Host "`$Arr Contents During Call:" $InputArray
}
[object[]]$Arr = [object[]]@($true, $false)
Write-Host "`$Arr Type Before Call:" ($Arr.GetType().FullName)
Write-Host "`$Arr Contents Before Call:" $Arr "`n"
$f.Invoke($Arr)
The new change produces the following output:
$Arr Type Before Call: System.Object[]
$Arr Contents Before Call: True False$Arr Type During Call: System.Object[]
$Arr Contents During Call: True
Powershell is only providing the anonymous function one element of my array. What is going on here?
boolean
when I clearly am giving it an object
array? Use:
$f.Invoke((, $Arr))
or, more PowerShell-idiomatically:
& $f $Arr
As for what you tried:
$f.Invoke($Arr)
passes the elements of array $Arr
as individual arguments.
Since your script block $f
defines only one parameter, only the first element of $Arr
is bound to that parameter, $InputArray
.
(, ($Arr))
works around that problem by wrapping the array in an auxiliary single-element array, which $f.Invoke()
then unwraps and therefore passes $Arr
as a single argument.
That said, using object methods in PowerShell is generally an awkward experience, given that the invocation syntax causes confusion with PowerShell's command syntax.
Often, it's possible to stay in the realm of PowerShell's commands and operators.
Specifically, the PowerShell-idiomatic way to invoke script blocks ({ ... }
) is to use &
, the call operator (to execute the script block in a child scope; alternatively .
, the dot-sourcing operator, (typically) executes directly in the caller's scope).
&
(and .
) use command syntax (argument parsing mode), where arguments are passed without parentheses and separated with whitespace rather than ,
- see this answer for more information.
Therefore, & $f $Arr
interprets $Arr
as the 1st and only argument to be passed as a whole to the script block.