powershell 在什么条件下展开管道中的项目?

2024-01-07

考虑以下:

function OutputArray{
    $l = @(,(10,20))
    $l
}

(OutputArray) -is [collections.ienumerable]
# C:\ PS> True
(OutputArray).Count
# C:\ PS> 2

$l 当它进入管道时被“展开” https://stackoverflow.com/q/695474/1404637. 这个答案指出 powershell 展开所有集合 https://stackoverflow.com/a/695483/1404637. 哈希表是一个集合 https://msdn.microsoft.com/en-us/library/system.collections.hashtable%28v=vs.110%29.aspx。然而,哈希表当然不受管道的影响:

function OutputHashtable{
    $h = @{nested=@{prop1=10;prop2=20}}
    $h
}

(OutputHashtable) -is [collections.ienumerable]
# C:\ PS> True
(OutputHashtable).Count
# C:\ PS> 1

此注释表明所有 IEnumerable 都转换为对象数组 https://stackoverflow.com/questions/695474/powershell-converts-values-returned-from-function-how-to-avoid-this#comment1681096_695474。然而,数组和哈希表都是可枚举的:

@(,(10,20)) -is [collections.ienumerable]
#True
@{nested=@{prop1=10;prop2=20}} -is [collections.ienumerable]
#True

powershell 将对象“展开”到管道中的具体条件是什么?


实证测试结果

我宁愿对这些结果有一个分析基础,但我需要一个答案,以便我可以继续前进。因此,以下是我进行实证测试的结果,以发现哪些集合是由 powershell 管道展开的,哪些不是:

列中的 True 表示可能发生一些展开。

StartingType                          ChangedInCmdlet^  ChangedWhenEmitted**
------------                          ---------------   ------------------
System.String                                           
System.Collections.ArrayList          True              True
System.Collections.BitArray           True              True
System.Collections.Hashtable
System.Collections.Queue              True              True
System.Collections.SortedList
System.Collections.Stack              True              True
System.Collections.Generic.Dictionary                   
System.Collections.Generic.List       True              True

这些是一行 powershell 的结果,如下所示:

$result = $starting | Cmdlet

^ The ChangedInCmdlet列表示的类型$starting当它出现在里面时是不同的Cmdlet.

** The ChangedWhenEmitted列表示的类型$result分配给 $result 时与在内部发出时不同Cmdlet.

某些类型可能存在一些细微差别。可以通过查看下面的测试脚本输出的详细信息来分析这种细微差别。整个测试脚本如下。

测试脚本

[System.Reflection.Assembly]::LoadWithPartialName('System.Collections') | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName('System.Collections.Generic') | Out-Null

Function BackThroughPipeline{
    [CmdletBinding()]
    param([parameter(position=1)]$InputObject)
    process{$InputObject}
}

Function EmitTypeName{
    [CmdletBinding()]
    param([parameter(ValueFromPipeline=$true)]$InputObject)
    process{$InputObject.GetType().FullName}
}

$objects = (New-Object string 'TenTwentyThirty'),
           ([System.Collections.ArrayList]@(10,20,30)),
           (New-Object System.Collections.BitArray 16),
           ([System.Collections.Hashtable]@{ten=10;twenty=20;thirty=30}),
           ([System.Collections.Queue]@(10,20,30)),
           ([System.Collections.SortedList]@{ten=10;twenty=20;thirty=30}),
           ([System.Collections.Stack]@(10,20,30)),
           (& {
               $d = New-Object "System.Collections.Generic.Dictionary``2[System.String,int32]"
               ('ten',10),('twenty',20),('thirty',30) | % {$d.Add($_[0],$_[1])}
               $d
           }),
           (& {
               $l = New-Object "System.Collections.Generic.List``1[int32]"
               10,20,30 | % {$l.Add($_)}
               $l
           })

$objects | 
    % {
        New-Object PSObject -Property @{
                StartingType  = $_.GetType().FullName
                StartingCount = $_.Count
                StartingItems = $_
                InCmdletType  = $_ | EmitTypeName
                InCmdletCount = ($_ | EmitTypeName).Count
                AfterCmdletType   = (BackThroughPipeline $_).GetType().FullName
                AfterCmdletItems  = (BackThroughPipeline $_)
                AfterCmdletCount  = (BackThroughPipeline $_).Count
                ChangedInCmdlet    = if ($_.GetType().FullName -ne ($_ | EmitTypeName) ) {$true};
                ChangedWhenEmitted = if (($_ | EmitTypeName) -ne (BackThroughPipeline $_).GetType().Fullname ) {$true}
            }
    }

Out-Collection Cmdlet

该测试最终使我创建了一个 cmdlet,该 cmdlet 有条件地将集合包装在牺牲数组中,以(希望)可靠地防止循环展开。该 cmdlet 称为Out-Collection并且在这个 github 存储库 https://github.com/alx9r/a9Foundations.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

powershell 在什么条件下展开管道中的项目? 的相关文章

随机推荐