函数参数位置突然表现得很奇怪

Gar*_*n82 2 powershell pipeline parameter-passing positional-parameter

代码:

这个例子说明了我的意思:

Function test{
    param(
    [parameter(Position = 0, ValueFromPipeline)]
    [string]$Param0,
    [parameter(Position = 1)]
    [ArgumentCompletions("Param1_Opt1", "Param1_Opt2")]
    [Array]$Param1 = ('Param1_Opt3', 'Param1_Opt4'),
    [switch]$NoHeader
    )
    "This is $Param0"
    "Header :$Param1"
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

很长一段时间以来,我一直依赖所有函数中的参数位置,今天在编写函数时,突然它停止了我使用它们的方式。上面的test函数演示了这个问题。

如果参数具有参数Position = 0属性并且也具有该ValueFromPipeline 属性。当它用于管道时。具有Position属性的下一个参数占据其位置。这也意味着接下来的参数ArgumenCompletions,例如"Param1_Opt1"/ "Param1_Opt2" get 建议。

但我根本没有得到这种行为。

Test "This is For Parameter Zero" "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One
Run Code Online (Sandbox Code Playgroud)

上面的代码按预期工作,第一个字符串正确分配给Param0,第二个字符串正确分配给Param1,更多Param1参数建议有效,但以下内容失败并出现错误,并且管道字符串被分配给Param1。参数完成也Param1不起作用:

"This is For Parameter Zero" | Test "This is For Parameter One"
---- Error ----
test: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
--- OutPut ----
This is For Parameter One
Header :Param1_Opt0 Param1_Opt0
Run Code Online (Sandbox Code Playgroud)

期望的输出:

Test "This is For Parameter Zero" "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One
Run Code Online (Sandbox Code Playgroud)

以上是我在正常使用中所期望的,以下是使用管道时以及Param1参数建议起作用的情况:

"This is For Parameter Zero" | Test "This is For Parameter One"

---- Ouput -----
This is For Parameter Zero
This is For Parameter One
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 5

圣地亚哥在评论中提供了关键点,但让我详细说明一下:

在基于管道的调用中,您需要使用命名参数来绑定到-Param1

# Note the required use of -Param1
"This is For Parameter Zero" | Test -Param1 "This is For Parameter One"
Run Code Online (Sandbox Code Playgroud)

这是必要的原因是参数绑定的顺序

  • 在命令开始执行之前,参数提供的输入首先被绑定。

  • 只有稍后,当管道输入处理开始时,才会对每个管道输入对象执行参数绑定。

  • 至于为什么PowerShell必须这样绑定参数:

    • 根据设计,传递给命令的参数是预先评估的,并且评估的结果在命令开始执行之前就绑定到目标参数一次。

    • 管道输入通常是事先未知的,因为它仅在执行提供输入的命令产生

    • 另外,由提供输入的命令发出的对象的数据类型通常是未知的,并且命令可以自由地发出不同类型的对象,因此每个发出的对象可以不同地绑定到接收命令的参数。

    • 简而言之:无法静态地预先确定管道输入如何绑定到参数,因此必须推迟到运行时,并且必须为每个输入对象单独执行。

所以:

  • "This is For Parameter Zero" | Test "This is For Parameter One"首先单独绑定参数, 而不考虑潜在的管道输入,并且,鉴于它是第一个位置参数,它绑定到参数"This is For Parameter One"-Param0

  • 然后,当管道输入处理开始时,PowerShell 尝试将管道对象 "This is For Parameter Zero"绑定到尚未绑定参数的参数,并且由于函数唯一的管道绑定参数 ,-Param0已经绑定,因此参数绑定失败,导致你看到的错误。

    • 通过参数名称绑定参数可以避免-Param1此问题。