PowerShell从函数返回单个元素数组

9
今天我注意到了PowerShell的一种有趣行为,并编写了以下代码来展示它。当您运行以下代码时:
function test()
{
    $a = @(1,2);
    Write-Host $a.gettype()
    return $a;
}

$b = test
Write-Host $b.gettype();

你所拥有的是:

System.Object[]
System.Object[]

然而,当你将代码更改为以下内容时:
function test()
{
    $a = @(1);
    Write-Host $a.gettype()
    return $a;
}

$b = test
Write-Host $b.gettype();

你将会得到:

System.Object[]
System.Int32

能否有人提供关于这个“功能”的更多细节?貌似PowerShell规范没有提到过这一点。

谢谢。


顺便说一下,我在PowerShell 2、3和4上都测试过这段代码。

3个回答

6

Powershell在某些情况下会自动“展开”数组,例如您的赋值语句:

PS> (test).GetType()
System.Object[]

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

PS> $b = test
System.Object[]
PS> $b.GetType()

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

您可以通过在赋值中明确引入一个数组来解决问题:

$b = ,(test)

3
函数定义中是否有一种方法来强制执行这个,而不是在调用程序中? - Scott Wegner
@Scott:据我所知,PowerShell没有这样的功能。请记住,PowerShell是一种脚本语言,它围绕着消耗和生成值列表构建 - 这是管道自然完成的任务。到目前为止,我发现唯一有价值的地方是在你离开PowerShell的优势并尝试编写类似C#的代码(或传递数组而不是对象数组,这沿着同样的路径)。因此,总体而言,我认为这甚至不是一个疏忽或设计错误,这样做很麻烦。 - Joey
在大多数情况下是正确的。在PowerShell中有些地方需要类型。我的情况是:我正在编写一个小的PowerShell模块,用于在使用New-WebServiceProxy的cmdlet中包装内部WCF端点。代理方法将输入作为由代理客户端生成的自定义类型,我有一个帮助方法来构建它们。当我期望我的辅助程序给我返回一个数组并且它给我一个单个元素或null时,这很麻烦。现在调用代码需要知道内部动态类型来生成自己的空数组。 - Scott Wegner
不是在函数定义中,而是有一种方法可以在函数内部实现这个功能。在函数的返回语句中使用逗号:return ,$value。以某种方式,即使通过赋值,它也会保留单元素数组。参见 - Jonathan Lidbeck

0

在使用变量之前,将其声明为数组。
然后在调用函数时使用 +=。

无论你返回什么,它都会被视为数组。

function test
{
    return [int]1
}

$b = @()
$b += test

$b.GetType()

结果:

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

另一种做法:
$b = @(test)

-2

它告诉你它是一个对象,因为从技术上讲它确实是。

PS C:\Users\Administrator> $arr = @(1,2,3,4,5)
PS C:\Users\Administrator> $arr.GetType()

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

请注意,BaseTypeSystem.Array
但是当您使用 Write-Host 输出它时,它只会告诉您它是一个 System.Object[]
PS C:\Users\Administrator> Write-Host $arr.GetType()
System.Object[]

像这样。

因此,根据上表,我们可以运行以下命令来查找BaseType,这是有逻辑意义的:

PS C:\Users\Administrator> Write-Host $arr.GetType().BaseType
System.Array

1
它告诉他们这是一个对象数组;请注意[] - Joey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接