如何将命名函数作为参数传递(scriptblock)

时间:2013-04-12 17:12:21

标签: powershell scriptblock

我们来看一下经典的一阶函数示例:

function Get-MyName { "George" }

function Say-Hi([scriptblock]$to) {
  Write-Host ("Hi "+(& $to))
}

这很好用:

Say-Hi { "Fred Flintstone" }

这不是:

Say-Hi Get-MyName

因为评估了Get-MyName,而不是作为值本身传递。如何将Get-MyName作为值传递?

4 个答案:

答案 0 :(得分:6)

您必须将Get-Myname作为脚本块传递,因为这就是您定义变量类型的方式。

Say-Hi ${function:Get-MyName}

答案 1 :(得分:2)

如果您准备牺牲[scriptblock]参数类型声明 那么还有一种方法,可以说是最简单的使用和有效的方法。只是 从参数中删除[scriptblock](或将其替换为[object]):

function Get-MyName { "George" }

function Say-Hi($to) {
  Write-Host ("Hi "+(& $to))
}

Say-Hi Get-MyName
Say-Hi { "George" }

所以现在$to可以是脚本块或命令名(不仅仅是一个函数,还有别名,cmdlet和脚本)。

唯一的缺点是Say-Hi的声明不是那么自我描述。 当然,如果您不拥有代码而无法更改代码,那么这就是 根本不适用。

我希望PowerShell有一个特殊类型,请参阅此suggestion。 在这种情况下,function Say-Hi([command]$to)将是理想的。

答案 2 :(得分:2)

这可能是一个更好的例子来说明问题和执行范围的细节。 @mjolinor的答案似乎很适合这个用例:

function Get-MyName($name) { $name; throw "Meh" }

function Say-Hi([scriptblock]$to) {
  try {
      Write-Host ("Hi "+(& $to $args)) # pass all other args to scriptblock
  } catch {
      Write-Host "Well hello, $_ exception!"
  }
}

命令及其输出:

PS C:\> Say-Hi ${function:Get-MyName} 'George'
Well hello, Meh exception

特别是,我正在使用这种模式来包装与片状远程SQL Server数据库连接一起工作的函数,这些函数会休眠,然后在最终成功或抛出更高异常之前重试几次。

答案 3 :(得分:1)

严格根据您的代码,正确的答案是:

Say-Hi {(Get-MyName)}

这将产生“嗨乔治”