powershell v2 函数,如何为第一个参数 w/o 指定第二个参数的默认值?
powershell v2 function, how to have a default value for the 1st argument w/o naming the 2nd?
问题很简单。我有一个带有两个参数的函数,我希望能够在它具有默认值时不提供第一个参数就可以调用它,而不命名第二个参数。
例如(这不是我真正的功能,而是一个简单的例子来说明我的意思)
function foo
{ param([int]$int=-1,[string]$str="''")
$int
$str
}
我希望强制参数列表中的类型将使 PS 将正确的值绑定到正确的参数,但它似乎并非如此
PS C:\> foo
-1
''
PS C:\> foo 1
1
''
PS C:\> foo 1 x
1
x
PS C:\> foo -str x
-1
x
PS C:\> foo x
foo : Impossible de traiter la transformation d'argument sur le paramètre «int». Impossible de convertir la valeur «x» en type «System.Int32». Erreur: «Le format de la chaîne
d'entrée est incorrect.»
Au caractère Ligne:1 : 5
+ foo x
+ ~
+ CategoryInfo : InvalidData : (:) [foo], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,foo
我想要的是 PS 吗?
编辑
这里有一个更好的例子来说明我正在尝试做的事情
测试.ps1
[cmdletbinding()]
param(
[parameter()]
[string[]]$___where=@('*')
)
function InvokeOn {
[cmdletbinding()]
param(
[string[]]
${___names}=@('*'),
[scriptblock]
${___block}
)
$___doExec = ($___names -contains '*')
foreach($___name in $___names) { $___doExec = ($___doExec -or ($___where -contains $___name)) }
if($___doExec) { &$___block }
}
$null = new-item alias:__LOG__ -value InvokeOn
__LOG__ c1 { Write-host '-- 1 --' }
__LOG__ c2 { Write-host '-- 2 --' }
__LOG__ c1,c2 { Write-host '-- 1 or 2 --' }
__LOG__ { Write-host 'always, defaulted' }
__LOG__ -___block { Write-host 'always, named' }
还有一些运行
PS C:\> .\test
always, named
PS C:\> .\test c1
-- 1 --
-- 1 or 2 --
always, named
PS C:\> .\test c2
-- 2 --
-- 1 or 2 --
always, named
PS C:\> .\test c2,c1
-- 1 --
-- 2 --
-- 1 or 2 --
always, named
如您所见,__LOG__ { Write-host 'always, defaulted' }
永远不会触发,因为 PS 将脚本块绑定到错误的参数。
参数名称是故意复杂的,甚至不应该被使用别名函数的开发人员知道。
交换参数是不切实际的,因为脚本块可能很长,即使对于短脚本块,也会使 __LOG__
触发的情况变得不那么可读。
解决方案
应用majkinetor的想法,我这样修改了我的代码
function InvokeOn {
[cmdletbinding()]
param(
[string[]]
${___names} = @('*'),
[scriptblock]
${___block}
)
if(!$PSBoundParameters.ContainsKey('___block')) { $___names,$___block = @('*'),[scriptblock]::create($___names[0]) }
$___doExec = ($___names -contains '*')
foreach($___name in $___names) { $___doExec = ($___doExec -or ($___where -contains $___name)) }
if($___doExec) { &$___block }
}
现在它按预期工作了:)
我考虑向用户隐藏参数名称并仅根据类型评估参数 Bad Idea™ 并且 强烈 推荐 反对这样做。
话虽如此,如果您出于某种不明原因绝对必须采用这种方式,我会完全放弃命名参数并改用 $args
automatic variable。
function foo {
# define default values for your "parameters"
$int = -1
$str = "''"
...
# evauluate $args and override default values
foreach ($arg in $args) {
switch ($arg.GetType().FullName) {
'System.Int32' { $int = $arg }
'System.String' { $str = $arg }
...
default { throw "Unrecognized type ${_}." }
}
}
# handle missing arguments if required
# Example:
# if ($args.Count -eq 0) { throw "No arguments provided." }
...
}
你可以这样做:
function foo
{
param ($int=-1,[string]$str="''")
if ($int.gettype().Name -eq 'String') { $str = $int; $int = -1 }
$int
$str
}
注意 - $int
不能有类型。
问题很简单。我有一个带有两个参数的函数,我希望能够在它具有默认值时不提供第一个参数就可以调用它,而不命名第二个参数。
例如(这不是我真正的功能,而是一个简单的例子来说明我的意思)
function foo
{ param([int]$int=-1,[string]$str="''")
$int
$str
}
我希望强制参数列表中的类型将使 PS 将正确的值绑定到正确的参数,但它似乎并非如此
PS C:\> foo
-1
''
PS C:\> foo 1
1
''
PS C:\> foo 1 x
1
x
PS C:\> foo -str x
-1
x
PS C:\> foo x
foo : Impossible de traiter la transformation d'argument sur le paramètre «int». Impossible de convertir la valeur «x» en type «System.Int32». Erreur: «Le format de la chaîne
d'entrée est incorrect.»
Au caractère Ligne:1 : 5
+ foo x
+ ~
+ CategoryInfo : InvalidData : (:) [foo], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,foo
我想要的是 PS 吗?
编辑
这里有一个更好的例子来说明我正在尝试做的事情
测试.ps1
[cmdletbinding()]
param(
[parameter()]
[string[]]$___where=@('*')
)
function InvokeOn {
[cmdletbinding()]
param(
[string[]]
${___names}=@('*'),
[scriptblock]
${___block}
)
$___doExec = ($___names -contains '*')
foreach($___name in $___names) { $___doExec = ($___doExec -or ($___where -contains $___name)) }
if($___doExec) { &$___block }
}
$null = new-item alias:__LOG__ -value InvokeOn
__LOG__ c1 { Write-host '-- 1 --' }
__LOG__ c2 { Write-host '-- 2 --' }
__LOG__ c1,c2 { Write-host '-- 1 or 2 --' }
__LOG__ { Write-host 'always, defaulted' }
__LOG__ -___block { Write-host 'always, named' }
还有一些运行
PS C:\> .\test
always, named
PS C:\> .\test c1
-- 1 --
-- 1 or 2 --
always, named
PS C:\> .\test c2
-- 2 --
-- 1 or 2 --
always, named
PS C:\> .\test c2,c1
-- 1 --
-- 2 --
-- 1 or 2 --
always, named
如您所见,__LOG__ { Write-host 'always, defaulted' }
永远不会触发,因为 PS 将脚本块绑定到错误的参数。
参数名称是故意复杂的,甚至不应该被使用别名函数的开发人员知道。
交换参数是不切实际的,因为脚本块可能很长,即使对于短脚本块,也会使 __LOG__
触发的情况变得不那么可读。
解决方案
应用majkinetor的想法,我这样修改了我的代码
function InvokeOn {
[cmdletbinding()]
param(
[string[]]
${___names} = @('*'),
[scriptblock]
${___block}
)
if(!$PSBoundParameters.ContainsKey('___block')) { $___names,$___block = @('*'),[scriptblock]::create($___names[0]) }
$___doExec = ($___names -contains '*')
foreach($___name in $___names) { $___doExec = ($___doExec -or ($___where -contains $___name)) }
if($___doExec) { &$___block }
}
现在它按预期工作了:)
我考虑向用户隐藏参数名称并仅根据类型评估参数 Bad Idea™ 并且 强烈 推荐 反对这样做。
话虽如此,如果您出于某种不明原因绝对必须采用这种方式,我会完全放弃命名参数并改用 $args
automatic variable。
function foo {
# define default values for your "parameters"
$int = -1
$str = "''"
...
# evauluate $args and override default values
foreach ($arg in $args) {
switch ($arg.GetType().FullName) {
'System.Int32' { $int = $arg }
'System.String' { $str = $arg }
...
default { throw "Unrecognized type ${_}." }
}
}
# handle missing arguments if required
# Example:
# if ($args.Count -eq 0) { throw "No arguments provided." }
...
}
你可以这样做:
function foo
{
param ($int=-1,[string]$str="''")
if ($int.gettype().Name -eq 'String') { $str = $int; $int = -1 }
$int
$str
}
注意 - $int
不能有类型。