【问题标题】:Powershell Try Catch in higher-order functionsPowershell Try Catch 在高阶函数中
【发布时间】:2017-05-01 23:40:15
【问题描述】:

我正在尝试捕获异常调用运行另一个函数的函数,如下所示:

$ErrorActionPreference = "Stop"
function f {
    $a = 1
    $b = $a / 0
}
function Main($f) {
    try {
        $f
    } catch [System.Exception] {
        "Caught exception"
    }
}
Main(f)

问题是异常没有被捕获并且powershell显示如下消息:

Attempted to divide by zero.
In C:\test.ps1:4 car:5
+     $b = $a / 0
+     ~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : RuntimeException

为什么即使$ErrorActionPreference = "Stop"在代码顶部也没有捕获到异常?

【问题讨论】:

  • 您的示例中没有高阶函数

标签: powershell exception try-catch


【解决方案1】:

好吧,您不是在调用 Main 函数,而是在调用 f 函数并将其输出作为 Main 的输入传递,然后调用 Main。使用 Set-PSDebug 看看。

Set-PSDebug -Trace 2

现在开始测试:

Main(f)

DEBUG:     ! CALL function '<ScriptBlock>'
DEBUG:     ! SET $ErrorActionPreference = 'Stop'.
DEBUG:   15+  >>>> Main(f)
DEBUG:    2+ function f  >>>> {

DEBUG:     ! CALL function 'f'
DEBUG:    3+  >>>> 1/0

虽然返回 1。

function f {
1/1
}
function Main($f) {
    try {
        $f
    } catch [System.Exception] {
        "Caught exception"
    }
}

Main(f)

这符合预期:

function f {
1/1
}
function Main($f) {
    try {
        $f/0
    } catch [System.Exception] {
        "Caught exception"
    }
}

Main(f)

编辑:为了澄清错误的第二个答案,这与预编译无关,并且可以使用以下代码轻松验证:

function f {
$a = 0
1/$a
}
function Main($input) {
    try {
        $input
    } catch [System.Exception] {
        "Caught exception"
    }
}

Main(f)

【讨论】:

  • 谢谢大家。我明白我的错误。
  • @guidros 很好,如果其中一个答案帮助您将其标记为答案,谢谢!
【解决方案2】:

问题出在Main(f)这一行。这样做是调用函数f 并尝试将结果传递给函数Main。当然,在它得到结果之前有一个异常并且管道永远不会进入 Main。您试图传递函数本身而不是结果。 PowerShell 没有直接执行此操作的好方法。它是一种脚本语言而不是功能语言。但是,您可以将 Main 的参数声明为 ScriptBlock 并调用它。 ScriptBlock 的操作很大程度上类似于函数对象。使用它会产生大致相同的效果。但是获取函数的 ScriptBlock 有点麻烦。这应该可以按预期工作并且是更标准的样式:

$ErrorActionPreference = "Stop"
function f {
    $a = 1
    $b = $a / 0
}

function Main {    
    param([ScriptBlock]$f)

    try {
        & $f
    } catch [System.Exception] {
        "Caught exception"
    }
}

Main -f { f }

因此,我们传递了一个新的脚本块,其中只包含对 f 的调用并调用该包装器。

请注意,我已经替换了 C 风格的函数调用语法。以我的经验,这种风格比它在 PowerShell 中的价值更麻烦。坚持 PowerShell 风格,事情通常会更清晰。

如果你真的想得到函数的ScriptBlock,你需要做这样的事情:

Main -f (get-command f).ScriptBlock

【讨论】:

    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    • 2013-07-09
    • 2021-01-26
    相关资源
    最近更新 更多