2015-12-02 19 views
2

请看下面的代码:如何确定仅在当前管道步骤中绑定的参数?

function g 
{ 
    [CmdletBinding()] 
    param 
    (
     [parameter(ValueFromPipelineByPropertyName = $true)]$x, 
     [parameter(ValueFromPipelineByPropertyName = $true)]$y, 
     [parameter(ValueFromPipelineByPropertyName = $true)]$z 
    ) 
    process 
    { 
     $retval = @{[email protected]{};[email protected]{};x=$x;y=$y;z=$z} 
     $PSBoundParameters.Keys | 
      % { $retval.psbp.$_ = $PSBoundParameters.$_ } 
     $PSCmdlet.MyInvocation.BoundParameters.Keys | 
      % { $retval.mibp.$_ = $PSCmdlet.MyInvocation.BoundParameters.$_} 
     return New-Object psobject -Property $retval 
    } 
} 

$list = (New-Object psobject -Property @{x=1;z=3}), 
     (New-Object psobject -Property @{x=$null;y=2}) 
$list | 
    g | 
    Select bp,x,y,z | 
    ft -AutoSize 

下面的输出运行脚本的结果:

psbp  mibp  x y z 
----  ----  - - - 
{z, x} {z, x} 1 3 
{y, z, x} {y, z, x} 2 

这似乎表明,这两个$PSBoundParameters$PSCmdlet.MyInvocation.BoundParameters包含势必使所有参数的累积远。

我相当肯定$x$z被束缚的第一步,和$x$y被绑定在第二个步骤,但我还没有找到一种以编程方式检索细节。

如何确定在当前管道步骤中绑定的参数?


为什么我在乎这件事?某些类型的参数验证比使用诸如参数集ValidateScript()等语言功能可以实现的要复杂得多。验证必须在函数体内执行。偶尔需要考虑一个未绑定的参数在语义上不同于将$null传递给相同的参数。通常通过询问$PSBoundParameters来实现绑定参数的检测。如果您只传递管道上的单个参数对象,这可以正常工作。但是,如果使用管道管道传输参数对象列表,则由于上述脚本显示的问题而导致该检测被阻止。这违反了最少原则的原则,因为当调用者碰巧通过将相同的对象管道到它来调用它时,在foreach循环内工作正常的函数的行为显着不同。

可以变通的作法是从foreach中调用受影响的功能,但我宁愿解决问题的所有调用,而不是完全放弃流水线。

+0

这是一个非常有趣的问题。你的最终目标是什么?也可以尝试使用'Trace-Command'并查看它是否可能揭示绑定过程的任何内容。 – briantist

+0

@briantist我为这个问题添加了一个解释。 – alx9r

回答

2

你可以记住通过命令行begin块内的全部参数,然后在process块结束时,您可以从当前输入对象界定参数清理$PSBoundParameters

function g 
{ 
    [CmdletBinding()] 
    param 
    (
     [parameter(ValueFromPipelineByPropertyName = $true)]$x, 
     [parameter(ValueFromPipelineByPropertyName = $true)]$y, 
     [parameter(ValueFromPipelineByPropertyName = $true)]$z 
    ) 
    begin 
    { 
     [email protected]($PSBoundParameters.Keys) 
    } 
    process 
    { 
     ... 

     @($PSBoundParameters.Keys) | 
      ? { $CommandLineBoundParameters -notcontains $_ } | 
      % { [void]$PSBoundParameters.Remove($_) } 
    } 
} 
+1

这看起来好像会起作用。我把一些正式的CI测试[在这里](https://github.com/alx9r/ToolFoundations/blob/2790e93d502cd92c4217c22cbf1fb1cc140836f6/EnvironmentTests/parameterBinding.Tests.ps1#L412-L471)。这些测试在PowerShell 2,4和5下通过。感谢您的帮助! :) – alx9r

+0

好的Pester测试@ alx9r! – briantist

+0

:)谢谢@briantist。 – alx9r