powerhell在什么情况下展开项目?

考虑以下几点:
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.

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...