数组 – 如何编写PowerShell高级函数,可以使用管道对象和对象获取参数值?

我正在编写一个函数Chunk-Object,它可以将一个对象数组块化为子数组.例如,如果我传递一个数组@(1,2,3,4,5)并为每个块指定2个元素,那么它将返回3个数组@(1,2),@(3,4)和@( 5).此外,如果用户希望在将每个元素块化为子数组之前处理它们,则可以提供可选的scriptblock参数.现在我的代码是:

function Chunk-Object()
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] [object[]] $InputObject,[Parameter()] [scriptblock] $Process,[Parameter()] [int] $ElementsPerChunk
    )

    Begin {
        $cache = @();
        $index = 0;
    }

    Process {
        foreach($o in $InputObject) {
            $current_element = $o;
            if($Process) {
                $current_element = & $Process $current_element;
            }
            if($cache.Length -eq $ElementsPerChunk) {,$cache;
                $cache = @($current_element);
                $index = 1;
            }
            else {
                $cache += $current_element;
                $index++;
            }
        }
    }

    End {
        if($cache) {,$cache;
        }
    }
}


(Chunk-Object -InputObject (echo 1 2 3 4 5 6 7) -Process {$_ + 100} -ElementsPerChunk 3)
Write-Host "------------------------------------------------"
(echo 1 2 3 4 5 6 7 | Chunk-Object -Process {$_ + 100} -ElementsPerChunk 3)

结果是:

PS C:\Users\a> C:\Untitled5.ps1
100
100
100
100
100
100
100
------------------------------------------------
101
102
103
104
105
106
107

PS C:\Users\a>

正如您所看到的,它适用于管道对象,但不适用于来自参数的值get.如何修改代码使其在两种情况下都能正常工作?

解决方法

不同之处在于,当您将数组传递给Chunk-Object时,该函数对作为一系列管道对象传递的数组中的每个元素执行一次进程块,而当您将该数组作为参数传递给-InputObject参数时,进程块对整个数组执行一次,整个数组被分配给$InputObject.

那么,让我们来看看命令的管道版本:

echo 1 2 3 4 5 6 7 | Chunk-Object -Process {$_ + 100} -ElementsPerChunk 3

这个工作的原因是,对于管道的每次迭代,$_被设置为管道中当前数组元素的值,它也被分配给$InputObject变量(作为单元素数组,由于[object []]类型转换.在这种情况下,foreach循环实际上是无关的,因为$InputObject数组每次调用进程块时总是有一个元素.你实际上可以删除循环并将$current_element = $o更改为$current_element = $InputObject,你会得到完全相同的结果.

现在,让我们检查将数组参数传递给-InputObject的版本:

Chunk-Object -InputObject (echo 1 2 3 4 5 6 7) -Process {$_ + 100} -ElementsPerChunk 3

这不起作用的原因是您传递给-Process参数的scriptblock包含$_,但foreach循环将每个元素分配给$o,并且$_未在任何地方定义.结果中的所有元素都是100,因为每次迭代都会将$current_element设置为scriptblock {$_ 100}的结果,当$_为null时,它总是计算为100.要证明这一点,请尝试将scriptblock中的$_更改为$o,然后您将获得预期的结果:

Chunk-Object -InputObject (echo 1 2 3 4 5 6 7) -Process {$o + 100} -ElementsPerChunk 3

如果您希望能够在scriptblock中使用$_,只需替换foreach($Input in $Input)中的foreach循环(使用$InputObject | %{.这样两个版本都可以工作,因为Chunk-Object函数在内部使用了一个管道,所以$_被顺序设置到数组的每个元素,无论是否为传入的一系列单个数组元素多次调用了进程块作为管道输入,或者只是一次用于多元素阵列.

更新:

我再次看着这个,注意到了这一点

$current_element = & $Process $current_element;

您似乎试图将$current_element作为参数传递给$Process中的scriptblock.这不起作用,因为传递给scriptblock的参数与函数中的参数大致相同.如果你调用MyFunction’foo’,那么’foo’不会自动分配给函数中的$_;同样地,& {$_ 100}’foo’没有将$_设置为’foo’.将您的scriptblock参数更改为{$args [0] 100},无论是否传递管道输入,您都将获得预期的结果:

Chunk-Object -InputObject (echo 1 2 3 4 5 6 7) -Process {$args[0] + 100} -ElementsPerChunk 3

请注意,虽然这个版本的scriptblock参数即使你保留foreach循环也能工作,但我仍然建议使用Foreach-Object($InputObject |%{),因为它通常效率更高,所以函数运行速度更快,大量数据的.

相关文章

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