Subexpression operator changes type of array elements?

I’ve encountered some surprising behavior with the subexpression operator $() changing the type of the result of the subexpression, and I was wondering if anyone can explain it.

If you create an array of Bytes, GetType() returns Byte, which is as you would expect. But if you apply the subexpression operator to the byte array, e.g. $($bytes).GetType(), the returned type is an array of Object. Why the change? Then, perhaps even stranger, retrieving the type of one of the elements of the Object array, as in ($bytes)[0].GetType(). returns a Byte value type.

Anyone know why the subexpression oeprator has this behavior?

PS C:\> $bytes = [System.Byte[]](1,2)
PS C:\> $bytes.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Byte[]                                   System.Array

PS C:\> $($bytes).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS C:\> $($bytes)[0].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Byte                                     System.ValueType

PS C:\> 

Hey, Gil!

Subexpressions were meant for a few specific use cases, where that outcome is essentially desired - as in embedding an expression into a double-quoted string. So some coercion goes on to support those kinds of uses.

Hey Gil,
I not sure if you were looking for a solution or just looking for understanding as to why it’s happening, but what you can do it typecast your subexpression.

$bytes = [System.Byte[]](1,2)

$bytes.GetType()
$bytes[0].GetType()
Write-Host "------------------------------"
$($bytes).GetType()
$($bytes)[0].GetType()
Write-Host "------------------------------"
([byte[]]$($bytes)).GetType()
([byte[]]$($bytes))[0].GetType()
Write-Host "------------------------------"

Results:

IsPublic IsSerial Name                                     BaseType                                                                                                      
-------- -------- ----                                     --------                                                                                                      
True     True     Byte[]                                   System.Array                                                                                                  
True     True     Byte                                     System.ValueType                                                                                              
------------------------------
True     True     Object[]                                 System.Array                                                                                                  
True     True     Byte                                     System.ValueType                                                                                              
------------------------------
True     True     Byte[]                                   System.Array                                                                                                  
True     True     Byte                                     System.ValueType                                                                                              
------------------------------

Thanks Don and Curtis!

Don, your comment about solving a particular use case makes sense, although the implementation still strikes me as somewhat bizarre. OTOH, that shouldn’t surprise anyone familiar with PowerShell. :slight_smile:

Curtis, as it turns out I could use expression grouping with parens in my situation, so I solved my problem that way. Good to know that forcing the type cast works.

-gil