我试图使用PS模块模拟类,如this回答中所述。但是,在{"实例方法"
中exit
似乎无法实现。{/ p>
$sb =
{
function bar
{
"bar"
}
function quux
{
exit
}
Export-ModuleMember -Function bar,quux
}
$foo = New-Module $sb -AsCustomObject
$foo.bar()
$foo.quux()
结果
bar
Exception calling "quux" with "0" argument(s): "System error."
At line:17 char:1
+ $foo.quux()
+ ~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ScriptMethodFlowControlException
答案 0 :(得分:0)
您可以抛出异常并使用trap
来捕获它并退出脚本:
trap{
exit
}
$sb =
{
function bar
{
"bar"
}
function quux
{
throw "Stopping execution"
}
Export-ModuleMember -Function bar,quux
}
$foo = New-Module $sb -AsCustomObject
$foo.bar()
$foo.quux()
答案 1 :(得分:0)
为什么会首先发生这种情况,为什么异常情况如此神秘?
您看到的行为似乎是 bug (自PowerShell 7.0起仍然存在;请参见this GitHub issue):
从附加到exit
实例的 脚本方法调用[pscustomobject]
-脚本方法是否是间接的通过New-Module -AsCustomObject
或直接通过
附加
Add-Member -MemberType ScriptMethod
-意外失败,并显示了您所看到的神秘错误:该错误不是退出,而是作为声明终止错误(请参见下文)和执行< em>默认情况下继续。
在 PowerShell 5+ class
上定义的方法 不受影响。
正确执行此操作的规范方法是什么?我确实想退出并停止所有进一步的执行,而不是恢复控制流程。我还需要能够返回退出代码。
通常,从{em> script 文件的顶级范围调用exit
,而不是从函数内部(无论是否在模块内部)调用。
请注意,exit
或者立即退出封闭脚本,或者,如果直接在交互式会话中调用该函数,则存在整个会话。 / p>
如果您的quux()
方法是从脚本内调用的,而您确实确实想立即退出该封闭脚本,则在PowerShell 4中使用 direct direct 解决方法 不是试图模拟PowerShell类并直接定义和调用quux
函数 。
但是, 间接间接解决方案是对Martin Brandl's helpful answer的throw
方法进行一些细微调整:
PowerShell不一致使用终止错误使解决方案变得复杂,该错误分为两类:
语句-终止错误,该错误(默认情况下)仅终止执行语句,然后继续执行。
脚本终止错误(更准确地说:运行空间终止错误),它们会终止整个执行(脚本及其所有调用者,以及调用PowerShell的CLI的情况(整个Powershell进程)。
this GitHub docs issue中描述了这种令人惊讶的区别以及PowerShell总体上令人惊讶的错误处理。
动态模块方法中使用的附加到[pscustomobject]
实例的脚本方法 仅能够生成声明-终止错误,而不是脚本终止错误。
同样, PowerShell 5+ class
方法的行为有所不同:它们创建脚本终止错误。
要实现总体的终止同时还报告退出代码 [1] ,您还需要在中执行以下操作呼叫者的范围:
exit $n
语句作为响应(在脚本作用域内将成功执行),其中$n
是所需的退出代码。您有两个选择:
在调用方的作用域中添加trap
语句,该语句会为语句终止和脚本终止错误触发,并调用exit $n
,其中$n
是所需的退出代码。
要这样做,对Martin答案的唯一调整是将trap { exit }
替换为
trap { exit 1 }
报告退出代码1
。
与throw
ing函数通信特定的退出代码需要额外的工作-见下文。
请注意,trap
很少使用,但是它可以根据您的情况提供直接的解决方案。
或者,在方法调用前后使用try
/ catch
语句或一组可能引发错误的语句,然后在exit
处理程序中调用catch
:
try { $foo.quux() } catch { exit 1 }
# Create a custom object with methods,
# via a dynamic module.
$foo = New-Module -AsCustomObject {
function bar
{
"bar"
}
function quux
{
# Throw a statement-terminating error with the desired exit code,
# to be handled by the `trap` statement in the caller's scope.
throw 5
}
}
# Set up the trap statement for any terminating error.
# Note: Normally, you'd place the `trap` statement at the
# beginning of the script.
trap {
# Get the exit code from the most recent error or default to 1.
# Note: $_ is a *wrapper* error record arund the original error record
# created with `throw`; however, the wrapper's .ToString() representation
# is the (string representation of) the original object thrown.
if (-not ($exitCode = $_.ToString() -as [int])) { $exitCode = 1 }
exit $exitCode
}
$foo.bar()
$foo.quux() # This triggers the trap.
# Getting here means that the script will exit with exit code 0
# (assuming no other terminating error occurs in the remaining code).
[1]如果脚本自动由于 script 终止错误而终止,那么基于class
的解决方案就会生成该脚本,退出代码总是 报告为1
(并显示错误消息),但是只有(如果脚本是通过PowerShell的CLI ({{ 1}}或powershell -file ...
);相反,在这种情况下,在交互式 PowerShell会话powershell -commmand ...
中未设置 (但会显示错误消息)。
因此,即使可以选择使用PS 5+解决方案,您仍然可能想捕获脚本终止错误,并将其显式转换为具有特定退出代码的$LASTEXITCODE
调用,如下所示。