考虑以下脚本:
function g
{
[CmdletBinding()]
param
(
[parameter(ValueFromPipelineByPropertyName = $true)]$x,
[parameter(ValueFromPipelineByPropertyName = $true)]$y,
[parameter(ValueFromPipelineByPropertyName = $true)]$z
)
process
{
$retval = @{psbp=@{};mibp=@{};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
当调用者碰巧通过管道将相同的对象传递给它来调用它时,循环的行为会大不相同。
我可以通过在 a 中调用受影响的函数来foreach
解决这个问题,但我宁愿解决所有调用的问题,也不愿完全放弃管道。