I have a strange behavior that I don't understand. are not all array created equal?
$a1=[object[]]::new(15)
$a1.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$a1.length
15
0..14|%{$a1[$_]=$_}
string formatting with the 10th element works as expected.
'{10}' -f $a1
10
but...
$a2=new-object object[] 15
$a2.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$a2.length
15
0..14|%{$a2[$_]=$_}
the very same string formatting request raise an error as if the $a2 array was too small
'{10}' -f $a2
Erreur lors de la mise en forme d’une chaîne : L'index (de base zéro) doit être supérieur ou égal à zéro et inférieur à la taille de la liste des arguments..
Au caractère Ligne:1 : 1
+ '{10}' -f $a2
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation : ({10}:String) [], RuntimeException
+ FullyQualifiedErrorId : FormatError
am I missing something? where am I wrong?
The behavior is a known bug:
Because New-Object is a cmdlet (command) rather than an expression (such as [object[]]::new(15)), its output object is wrapped in a [psobject] instance.
Usually, these invisible [psobject] wrappers are benign, and the wrapper presents as if it were the wrapped object itself.
Situationally, however, the presence of such a wrapper interferes with functionality, such as in your case:
The -f operator doesn't recognize a [psobject]-wrapped array as such, which causes the problem you saw:
To simulate the problem with an array artificially wrapped in [psobject]:
# !! Error:
# "Index (zero based) must be greater than or equal to zero and
# less than the size of the argument list."
# The [psobject]-wrapped array is treated as a *single* object so -f
# sees no *2nd* value ({1})
# Omitting the [psobject] cast works as expected.
'{1}' -f [psobject] ('a', 'b')
# Ditto, with New-Object,
# which *invariably and implicitly* returns the array in a [psobject] wrapper.
'{1}' -f (New-Object string[] 2)
Relevant GitHub issues:
GitHub issue #14355: The bug at hand.
GitHub issue #5579: General discussion and other cases where the situational [psobject] wrapping causes problems.
Workarounds:
As you've noted, using a constructor expression, via the intrinsic static ::new() method PowerShell exposes on all .NET types (which requires v5+ of PowerShell) - such as [object[]]::new(15) - does not exhibit the problem, because no invisible [psobject] wrapper is then involved.
New-Object in general.In PowerShell v4-, use .psobject.BaseObject to work around the problem, via the intrinsic psobject property, which returns the wrapped array:
$a2 = (New-Object object[] 15).psobject.BaseObject
'{10}' -f $a2 # OK
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With