Powershell在高阶函数中尝试捕获

时间:2016-12-16 08:12:41

标签: powershell exception try-catch

我试图捕获异常,调用一个运行另一个函数的函数:

$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"位于代码顶部也未捕获异常?

2 个答案:

答案 0 :(得分:3)

问题出在这一行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

答案 1 :(得分: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)
相关问题