Powershell Array Types - System.Object [] vs. Arrays with Specific Types

Why casting GetType().Namein an array of strings returns Object[], and not String[]? It is like any type of element, for example it Import-Csvwill give you Object[], but each element is PSCustomObject.

Here is an example with an array String

$x = @('a','b','c')

$x[0].GetType().Name #String
$x.GetType().Name #Object[]
+4
source share
2 answers

Because you did not specify the data type of the array explicitly.

For example, assigning an integer $x[1]will work because the type is an array Object[].

If you specify the data type when building the array, you cannot later assign values ​​to an incompatible type:

C:\PS> [int[]] $myArray = 12,64,8,64,12

C:\PS> $myArray.GetType()

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



C:\PS> $myArray[0] = "asd"
Cannot convert value "asd" to type "System.Int32". Error: "Input string was not in a c
orrect format."
At line:1 char:1
+ $myArray[0] = "asd"
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastFromStringToInteger
+3

PetSerAl .

, PowerShell System.Object[] :

PowerShell :

  • ( $null),
  • .

, () [object[]] ([System.Object[]]), System.Object - .NET, .

, [object[]], [string], [int], [datetime] $null .

$arr = 'hi', 42, (Get-Date), $null  # @(...) is not needed; `, <val>` for a 1-elem. arr.

:

  • , ,

  • , @(...)

  • , 2 , , (...)

System.Object[] - , .


PowerShell , :

  • : , ( , ), ; :.

    $intArray = 1, 2      # An array of [int] values.
    $intArray[0] = 'one'  # !! Works, because a [System.Object[]] array can hold any type.
    
  • [System.Object[]] , [int], - .

PowerShell .NET, , , , :

[int[]] $intArray = 1, 2  # A type-constrained array of [int] variable.
$intArray[0] = 'one'      # BREAKS: 'one' can't be converted to an [int]

, - $intArray = [int[]] (1, 2) - , , (, $intArray = 'one', 'two' ).

: [int[]] 1, 2 , , , ([int[]] 1), 2, [object[]], [int[]] 1.
@(...) [1] , , , , .


PowerShell , , :

  • PowerShell , :

    [string[]] $a = 'one', 'two'
    $a[0] = 1    # [int] 1 is quietly coerced to [string]
    
    # The coercion happens even if you use a cast:
    [string[]] $a = 'one', 'two'
    $a[0] = [int] 1    # Quiet coercion to [string] still happens.
    

    . , - [int] 1 - , . - - , - , , PowerShell, - . [2]

    , , [string[]] - .
    , () , , [int[]] $arr = 1, 2; $arr[0] = 'one' # error

  • " " [object[]]:

    PowerShell "" +.
    (), [object[]], :

    $intArray = [int[]] (1, 2)
    ($intArray + 4).GetType().Name # !! -> 'Object[]'
    $intArray += 3 # !! $intArray is now of type [object[]]
    
    # To avoid the problem...
    # ... use casting:
    ([int[]] ($intArray + 4)).GetType().Name # -> 'Int32[]'
    # ... or use a type-constrained variable:
    [int[]] $intArray = (1, 2) # a type-constrained variable
    $intArray += 3 # still of type [int[]], due to type constraint.
    
  • [object[]]:

    , ( ) [object[]], :

    # A specifically-typed array:
    # Note that whether or not `return` is used makes no difference.
    function foo { return [int[]] (1, 2) }
    # Important: foo inside (...) is a *command*, not an *expression*
    # and therefore a *pipeline* (of length 1)
    (foo).GetType().Name # !! -> 'Object[]'
    
    # A different collection type:
    function foo { return [System.Collections.ArrayList] (1, 2) }
    (foo).GetType().Name # !! -> 'Object[]'
    
    # Ditto with a multi-segment pipeline:
    ([System.Collections.ArrayList] (1, 2) | Write-Output).GetType().Name # !! -> 'Object[]'
    

    , PowerShell : ; , ( 1).

    , PowerShell , - , (...), [object[]].

    PowerShell , IEnumerable , , IDictionary .
    , PowerShell hashtables ([hashtable]) - ( PSv3 + [ordered] @{...}), [System.Collections.Specialized.OrderedDictionary]) ( -) , .GetEnumerator().

  • PowerShell :

    : , PowerShell , .

    # The examples use single-element array ,1 
    # constructed with the unary form of array-construction operator ","
    # (Alternatively, @( 1 ) could be used in this case.)
    
    # Function call:
    function foo { ,1 }
    (foo).GetType().Name # -> 'Int32'; single-element array was *unwrapped*
    
    # Pipeline:
    ( ,1 | Write-Output ).GetType().Name # -> 'Int32'
    
    # To force an expression into an array, use @(...):
    @( (,1) | Write-Output ).GetType().Name # -> 'Object[]' - result is array
    

    , @(...): , ( ) : < > , [object[]] 1 .
    , , , [object[]], :
    $a1 = 1, 2; $a2 = @( $a1 ); [object]::ReferenceEquals($a1, $a2)
    $false, , $a1 $a2 .

    :

    • (...), - , :

      • - (- ), ; , ([System.Collections.ArrayList] (1, 2)) -is [System.Collections.ArrayList] ([int[]] (1,2)) -is [int[]] $true - .

      • - (- ), ; .:
        (&{ , 1 }) -is [int] $true ( ), (& { [int[]] (1, 2) }) -is [object[]] ( [int[]] [object[]]) $true, & .

    • () $(...), , : $(,1) -is [int] $([System.Collections.ArrayList] (1, 2)) -is [object[]] $true.

  • script:

    , , .

    , , PowerShell [object[]].

    , , , PowerShell :

    # Wrap array list in regular array with leading ","
    function foo { , [System.Collections.ArrayList] (1, 2) }
    # The call to foo unwraps the outer array and assigns the original
    # array list to $arrayList.
    $arrayList = foo
    # Test
    $arrayList.GetType().Name # -> 'ArrayList'
    

    PSv4 + Write-Output -NoEnumerate:

    function foo { write-output -NoEnumerate ([System.Collections.ArrayList] (1, 2)) }
    $arrayList = foo
    $arrayList.GetType().Name # -> 'ArrayList'
    

[1] , @(...) , , .
PSv5.1 ( , , ) , , - @() @() - . . @(...) :
* : (@( 1 ) (@( 1, 2 ))). , ,: 1, 2 vs. , 1.
* , - @(...) ( , ).
* , $(...) @(...) .

[2] PetSerAl , , PowerShell :

# Define a simple type that implements an interface
# and a method that has 2 overloads.
Add-Type '
  public interface I { string M(); } 
  public class C : I {
           string I.M()       { return "I.M()"; } 
    public string M()         { return "C.M()"; } 
    public string M(int i)    { return "C.M(int)"; } 
    public string M(object o) { return "C.M(object)"; } 
  }
'
# Instantiate the type and use casts to distinguish between
# the type and its interface, and to target a specific overload.
$C = New-Object C
$C.M()        
([I]$C).M()       # cast is respected
$C.M(1)
$C.M([object]1)   # cast is respected

+9

All Articles