powershell v2函数,如何为第一个参数设置一个默认值,而没有命名第二个?

时间:2016-04-02 23:16:53

标签: powershell powershell-v2.0

问题很简单。我有一个带有两个参数的函数,我希望能够在没有第一个函数的情况下调用它,因为它有默认值而没有命名第二个。 例如(这不是我真正的功能,而是一个显示我的意思的简单例子)

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吗?

修改

这是我正在尝试做的更好的例子

test.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会将脚本块绑定错误的参数。

参数名称目的很复杂,开发人员甚至不应该使用别名函数知道。

交换参数是不切实际的,因为scriptblock可能很长,即使是短的,也可以使__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 }
}

现在它按预期工作:)

2 个答案:

答案 0 :(得分:3)

您可以执行以下操作:

 function foo 
 { 
    param ($int=-1,[string]$str="''") 
    if ($int.gettype().Name -eq 'String') { $str = $int; $int = -1 }
    $int
    $str
 }

注意 - $int必须没有类型。

答案 1 :(得分:0)

我考虑隐藏用户的参数名称并仅根据其类型评估参数 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." }

  ...
}