powershellreturn-typegeneric-list

[System.Collections.Generic.List[string]] as return value


I have a need/want to return a [System.Collections.Generic.List[string]] from a function, but it is being covered into a System.Object[]

I have this

function TestReturn {
    $returnList = New-Object System.Collections.Generic.List[string]
    $returnList.Add('Testing, one, two')

    return ,@($returnList)
}

$testList = TestReturn
$testList.GetType().FullName

which returns it as a System.Object[], and if I change the return line to

return [System.Collections.Generic.List[string]]$returnList

or

return [System.Collections.Generic.List[string]]@($returnList)

it returns a [System.String] when there is one item in the list, and a System.Object[] if there is more than one item, in both cases. Is there something odd with a list that it can't be used as a return value?

Now, oddly (I think) it DOES work if I type the variable that receives the value, like this.

[System.Collections.Generic.List[string]]$testList = TestReturn

But that seems like some weird coercion and it doesn't happen with other data types.


Solution

  • If you remove the array subexpression @(...) and just precede with a comma. The below code seems to work:

    function TestReturn {
        $returnList = New-Object System.Collections.Generic.List[string]
        $returnList.Add('Testing, one, two')
    
        return , $returnList
    }
    
    $testList = TestReturn
    $testList.GetType().FullName
    

    Note: technically this causes the return of [Object[]] with a single element that's of type [System.Collections.Generic.List[string]]. But again because of the implicit unrolling it sort of tricks PowerShell into typing as desired.

    On your later point, the syntax [Type]$Var type constrains the variable. It's basically locking in the type for that variable. As such subsequent calls to .GetType() will return that type.

    These issues are due to how PowerShell implicitly unrolls arrays on output. The typical solution, somewhat depending on the typing, is to precede the return with a , or ensure the array on the call side, either by type constraining the variable as shown in your questions, or wrapping or casting the return itself. The latter might look something like:

    $testList = [System.Collections.Generic.List[string]]TestReturn
    $testList.GetType().FullName
    

    To ensure an array when a scalar return is possible and assuming you haven't preceded the return statement with , , you can use the array subexpression on the call side:

    $testList = @( TestReturn )
    $testList.GetType().FullName
    

    I believe this answer deals with a similar issue