我在PowerShell中有一个高级功能,大致如下所示:
function Foo {
[CmdletBinding]
param (
[int] $a = 42,
[int] $b
)
}
这个想法是它可以用两个,一个或没有参数运行。但是,成为可选的第一个参数是第一个。因此,以下方案可以运行该功能:
Foo a b # the normal case, both a and b are defined
Foo b # a is omitted
Foo # both a and b are omitted
但是,通常PowerShell会尝试将单个参数放入 a 中。所以我考虑明确指定参数位置,其中 a 将位置0和 b 位置1.但是,仅允许指定 b 我尝试将 a 放入参数集。但是 b 需要一个不同的位置,具体取决于当前使用的参数集。
任何想法如何妥善解决?我想保留参数名称(实际上不是 a 和 b ),因此使用$args
可能是最后的手段。我可能可以定义两个参数集,一个有两个必需参数,一个有一个可选参数,但我猜参数名称在这种情况下必须不同,那么,对吗?
答案 0 :(得分:5)
关于如何妥善解决这个问题的想法?不,我argued for a similar feature如果位置0的参数是管道绑定的,那么任何其他参数的“位置”会向下滑动,这样你就可以继续提供位置参数,而不必诉诸于所有命名参数。该团队认为这对于人们来说太混乱了 - 有参数转移位置。此行为是将管道绑定参数放在位置参数末尾的一个很好的理由。 : - )
带有高级功能的BTW,$ args不是一个选项。有点像$ _ - 它不适用。请使用ValueFromRemainingArguments
代替,例如:
[Parameter(ValueFromRemainingArguments=$true)]
$rest
答案 1 :(得分:2)
我担心你无法做到这一点。你可以得到的最接近的是必须命名第一个参数。可选的未命名位置参数必须是集合中的最后一个。
function test-optional {
[cmdletbinding(defaultparametersetname="SingleOrNone")]
param(
[parameter(
parametersetname="Both",
mandatory=$true,
position=1)]
[int]$A,
[parameter(
parametersetname="Both",
mandatory=$false,
position=2)]
[parameter(
parametersetname="SingleOrNone",
mandatory=$false,
position=1)]
[int]$B
)
end {
"parameterset: {0}; a: $a; b: $b" -f $pscmdlet.parametersetname, $a, $b
}
}
test-optional 1 # ok
test-optional 3 4 # fail
test-optional -a 3 4 # ok
test-optional -a 1 # ok
test-optional -b 1 # ok
test-optional -a 1 -b 2 # ok
test-optional # ok
答案 2 :(得分:0)
您可以使用动态参数(在“about_Functions_Advanced_Parameters”中记录)来执行此操作,这可能是“正确的”解决方案。但是根据你的论点的复杂性,你可以通过几种方式达到同样的效果。
您可以使用正确的参数排列来递归调用函数:
function ff($a, $b) {
if (!$PSBoundParameters.ContainsKey('b')) {
ff -b $a; return
}
# main logic
"a: $a"
"b: $b"
}
这导致:
PS C:\Users\Droj> ff one two
a: one
b: two
PS C:\Users\Droj> ff one
a:
b: one
PS C:\Users\Droj> ff
a:
b:
但是,这不允许您为参数定义不同的类型或验证。因此,如果您需要,另一个选择是将主逻辑包装在脚本块中,并根据传入的内容传入正确的参数。如下所示:
function ff() {
param($a, $b)
$go = {
param($a, $b)
"a: $a"
"b: $b"
}
if (!$PSBoundParameters.ContainsKey('b')) {
&$go -b $a
}
else {
&$go @PSBoundParameters
}
}
...导致相同的输出。
希望有所帮助!