【问题标题】:How to pass a named function as a parameter (scriptblock)如何将命名函数作为参数传递(脚本块)
【发布时间】:2013-04-12 17:12:20
【问题描述】:

我们以经典的一阶函数为例:

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 作为值传递?

【问题讨论】:

    标签: powershell scriptblock


    【解决方案1】:

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

    Say-Hi ${function:Get-MyName}
    

    【讨论】:

    • 这与Say-Hi {Get-MyName} 有何不同?除了[scriptblock],还有其他类型允许传递命名函数吗?
    • 这种情况下没有区别,因为返回值和函数的scriptblock定义是一样的。您要传递哪一个,函数的脚本块还是调用该脚本块的返回值?
    • 我想传递函数本身,就像在 javascript 或任何使用委托的 .net 语言中所做的一样
    • 好的。我们就是这么做的。函数的“值”是它的脚本块的内容。在这种情况下,脚本块就是“George”。
    • 这不太正确,假设 Get-MyName 带参数,在您的版本中,如果您直接传递函数,则必须知道调用它的所有参数并手动转发它们(就像在 js 或 c# 中一样)它的参数是从内部调用的任何参数 Say-Hi
    【解决方案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) 将是理想的选择。

    【讨论】:

      【解决方案3】:

      这可能是一个更好的例子来说明问题和执行范围的细节。 @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 数据库连接一起工作的函数,该连接会休眠,然后重试几次,最终成功或引发更高的异常。

      【讨论】:

        【解决方案4】:

        严格根据你的代码,正确答案是这样的:

        Say-Hi {(Get-MyName)}
        

        这将产生“Hi George”

        【讨论】:

        • 谢谢!你对这个语法和上面@mjolinor 的语法有什么区别吗?
        • 正如@SamDevx 所说“严格基于您的代码”,没有太大区别。但是如果函数有参数,那么以这种方式带参数调用就不是那么简单了。
        • @GeorgeMauer 不同之处在于这里传递了一个新块,其中调用了Get-MyName。在 mjolinor 的示例中,直接引用了 Get-MyName 传递的函数。 (使用参数,这种变化可以写成Say-Hi { Get-MyName @args },而 mjolinor 无需修改即可工作。)
        猜你喜欢
        • 2012-06-29
        • 2018-07-23
        • 2018-01-06
        • 2016-01-17
        • 2019-11-06
        • 2023-02-03
        • 1970-01-01
        • 2017-08-04
        • 1970-01-01
        相关资源
        最近更新 更多