我试图捕获异常,调用一个运行另一个函数的函数:
$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"
位于代码顶部也未捕获异常?
答案 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)