Why and how are these two $null values different?

前端 未结 3 1539
天涯浪人
天涯浪人 2020-11-30 14:20

Apparently, in PowerShell (ver. 3) not all $null\'s are the same:

    >function emptyArray() { @() }
    >$l_t = @() ; $l_t.Count
0
    &g         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-30 14:37

    When you return a collection from a PowerShell function, by default PowerShell determines the data type of the return value as follows:

    • If the collection has more than one element, the return result is an array. Note that the data type of the return result is System.Array even if the object being returned is a collection of a different type.
    • If the collection has a single element, the return result is the value of that element, rather than a collection of one element, and the data type of the return result is the data type of that element.
    • If the collection is empty, the return result is $null

    $l_t = @() assigns an empty array to $l_t.

    $l_t2 = emptyArray assigns $null to $l_t2, because the function emptyArray returns an empty collection, and therefore the return result is $null.

    $l_t2 and $l_t3 are both null, and they behave the same way. Since you've pre-declared $l_t as an empty array, when you add either $l_t2 or $l_t3 to it, either with the += operator or the addToArray function, an element whose value is **$null* is added to the array.

    If you want to force the function to preserve the data type of the collection object you're returning, use the comma operator:

    PS> function emptyArray {,@()}
    PS> $l_t2 = emptyArray
    PS> $l_t2.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Object[]                                 System.Array
    
    PS> $l_t2.Count
    0
    

    Note: The empty parentheses after emtpyArray in the function declaration is superfluous. You only need parentheses after the function name if you're using them to declare parameters.


    An interesting point to be aware of is that the comma operator doesn't necessarily make the return value an array.

    Recall that as I mentioned in the first bullet point, by default the data type of the return result of a collection with more than one element is System.Array regardless of the actual data type of the collection. For example:

    PS> $list = New-Object -TypeName System.Collections.Generic.List[int]
    PS> $list.Add(1)
    PS> $list.Add(2)
    PS> $list.Count
    2
    PS> $list.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     List`1                                   System.Object
    

    Note that the data type of this collection is List`1, not System.Array.

    However, if you return it from a function, within the function the data type of $list is List`1, but it's returned as a System.Array containing the same elements.

    PS> function Get-List {$list = New-Object -TypeName System.Collections.Generic.List[int]; $list.Add(1); $list.Add(2); return $list}
    PS> $l = Get-List
    PS> $l.Count
    2
    PS> $l.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Object[]                                 System.Array
    

    If you want the return result to be a collection of the same data type as the one within the function that you're returning, the comma operator will accomplish that:

    PS> function Get-List {$list = New-Object -TypeName System.Collections.Generic.List[int]; $list.Add(1); $list.Add(2); return ,$list}
    PS> $l = Get-List
    PS> $l.Count
    2
    PS> $l.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     List`1                                   System.Object
    

    This isn't limited to array-like collection objects. As far as I've seen, any time PowerShell changes the data type of the object you're returning, and you want the return value to preserve the object's original data type, you can do that by preceding the object being returned with a comma. I first encountered this issue when writing a function that queried a database and returned a DataTable object. The return result was an array of hashtables instead of a DataTable. Changing return $my_datatable_object to return ,$my_datatable_object made the function return an actual DataTable object.

提交回复
热议问题