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

时间:2015-02-24 17:38:52

标签: powershell collections ienumerable pipeline

请考虑以下事项:

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

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

$l is "unrolled" when it enters the pipelineThis answer states that powershell unrolls all collectionsA hashtable is a collection。但是,散列表当然不受管道的影响:

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

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

This comment suggests that it is all IEnumerable that are converted to object arrays。但是,数组和散列表都是不可数的:

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

究竟什么是powershell"展开的条件"对象进入管道?

1 个答案:

答案 0 :(得分:10)

经验测试结果

我宁愿对这些结果有一个分析基础,但我需要一个答案,所以我可以继续前进。因此,以下是我在实证测试中的结果,以发现哪些集合由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

^ ChangedInCmdlet列表示$starting出现在Cmdlet内时ChangedWhenEmitted的类型不同。

** $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} } } 内部发布时被分配给$ result时会有所不同。

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

测试脚本

Out-Collection

Out-Collection Cmdlet

此测试最终促使我创建了一个cmdlet,它有条件地将牺牲数组中的集合包装起来(希望)可靠地防止循环展开。该cmdlet名为{{1}},位于this github repository