考虑以下几点:
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 pipeline. This answer states that powershell unrolls all collections. A 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.但是,数组和散列表都是可以的:
@(,20)) -is [collections.ienumerable] #True @{nested=@{prop1=10;prop2=20}} -is [collections.ienumerable] #True
究竟是什么情况下,力量“展开”对象进入管道?
实证检验结果
我宁愿对这些结果有分析依据,但我需要一个答案,以便我继续前进.所以,这里是我的一个经验性测试的结果,以发现哪些集合由powershell的管道展开,哪些不是:
在列中表示可能有一些展开.
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
这些是一系列powerhell的结果,如下所示:
$result = $starting | Cmdlet
^ ChangedInCmdlet列表示在Cmdlet中显示$start的类型是不同的.
** ChangedWhenEmitted列表示当$result在Cmdlet中发出时被分配给$result时,$result的类型不同.
有些类型可能有一些细微差别.可以通过查看以下测试脚本输出的细节来分析这个细微差别.整个测试脚本如下.
测试脚本
[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,([System.Collections.SortedList]@{ten=10;twenty=20;thirty=30}),([System.Collections.Stack]@(10,(& { $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,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称为Out-Collection,为this github repository.