Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

powershell, difference between [object[]]::new(10) and new-object object[] 10

Tags:

powershell

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?

like image 363
Peyre Avatar asked Oct 25 '25 01:10

Peyre


1 Answers

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.

    • Given that this method is more efficient and uses the familiar method syntax used in constructor calls, it is worth preferring it to 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
    
like image 88
mklement0 Avatar answered Oct 26 '25 18:10

mklement0



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!