我想了解为什么以下代码打印出来"我不应该打印!!"
try块中的代码抛出一个错误,因为它的errorAction变量设置为stop,Ppowershell将执行相应的catch块。
在catch测试中,函数调用将失败(因为测试函数param属性validateSet不包含" fasdfsd")并抛出明显的非终止异常:ParameterArgumentValidationError
我现在期望在测试函数调用之后执行恢复,打印"捕获异常"并退出,但它跳出catch块并继续执行打印"我不应该打印!!"。
我错过了什么?
谢谢, 的Davide
function test-function{
[CmdletBinding()]
PARAM(
[Parameter(Mandatory)]
[ValidateSet('OnlyAcceptThisStringAndNothingElse')]
[ValidateNotNullOrEmpty()]
[string]$param
)
write-output "Executed"
}
try{
## throws an error to enter the catch block
get-childitem nonexisting -ea stop
}
catch{
## test-function does not accept this param and throws an error
test-function -param "fasdfsd"
## this should be executed anyway but it isn't
write-output "caught exception"
## the script should quit here
exit
}
## this Should not have been executed but it is
write-output "I shouldn't be printed!!"
答案 0 :(得分:0)
@beatcracker 如果一切正常,那么在非。之后 终止异常,执行应继续下一步 写入输出的指令"捕获异常"不久之后 命令"退出"哪个应该退出剧本。
- Davide Talesco
我同意,我对此并不清楚。我的意思是它始终以这种方式工作 - 必须将catch块中的所有内容包装到另一个try / catch中,否则它将在非终止错误时默默地退出catch scriptblock并继续执行下一个代码。
<小时/> 下面不是一个真正的答案,只是一个希望的蠢货,一个更熟练的人可以理解它。 虽然我无法理解为什么会这样做,但我认为我已将其本地化为
System.Management.Automation
汇编(public class ScriptBlock
)中的代码:
internal void InvokeWithPipe(bool useLocalScope, bool writeErrors, object dollarUnder, object input, object scriptThis, Pipe outputPipe, ref ArrayList resultList, params object[] args)
{
ExecutionContext contextFromTLS = this.GetContextFromTLS();
if (contextFromTLS.CurrentPipelineStopping)
{
throw new PipelineStoppedException();
}
ParseTreeNode codeToInvoke = this.GetCodeToInvoke();
if (codeToInvoke != null)
{
InvocationInfo invocationInfo = new InvocationInfo(null, codeToInvoke.NodeToken, contextFromTLS);
contextFromTLS.Debugger.PushMethodCall(invocationInfo, this);
bool flag = false;
ScriptInvocationContext oldScriptContext = null;
Pipe shellFunctionErrorOutputPipe = null;
CommandOrigin scopeOrigin = contextFromTLS.EngineSessionState.currentScope.ScopeOrigin;
Exception exception = null;
SessionStateInternal engineSessionState = contextFromTLS.EngineSessionState;
ActivationRecord oldActivationRecord = null;
try
{
ScriptInvocationContext scriptContext = new ScriptInvocationContext(useLocalScope, scriptThis, dollarUnder, input, args);
this.EnterScope(contextFromTLS, scriptContext, out oldScriptContext, out oldActivationRecord);
shellFunctionErrorOutputPipe = contextFromTLS.ShellFunctionErrorOutputPipe;
if (!writeErrors)
{
contextFromTLS.ShellFunctionErrorOutputPipe = null;
}
contextFromTLS.EngineSessionState.currentScope.ScopeOrigin = CommandOrigin.Internal;
if (!string.IsNullOrEmpty(this.File))
{
contextFromTLS.Debugger.PushRunning(this.File, this, false);
flag = true;
}
codeToInvoke.Execute(null, outputPipe, ref resultList, contextFromTLS);
}
catch (ReturnException exception2)
{
if (!this._isScriptBlockForExceptionHandler)
{
ParseTreeNode.AppendResult(contextFromTLS, exception2.Argument, null, ref resultList);
}
else
{
exception = exception2;
}
}
finally
{
if (flag)
{
contextFromTLS.Debugger.PopRunning();
}
contextFromTLS.ShellFunctionErrorOutputPipe = shellFunctionErrorOutputPipe;
contextFromTLS.EngineSessionState.currentScope.ScopeOrigin = scopeOrigin;
try
{
this.LeaveScope(contextFromTLS, oldScriptContext, engineSessionState, oldActivationRecord);
}
finally
{
contextFromTLS.Debugger.PopMethodCall();
}
}
if (exception != null)
{
throw exception;
}
}
}
catch的Scriptblocks是通过内部密封的_isScriptBlockForExceptionHandler
方法true
将ExceptionHandlerNode
设置为Invoke
创建的,该方法从上述方法调用CreateExceptionHandler
公共课ScriptBlock
:
internal static ScriptBlock CreateExceptionHandler(ParseTreeNode body, Token token, int pipelineSlots, int variableSlots)
{
return new ScriptBlock(token, null, null, null, null, body, null, false, null, null, null, pipelineSlots, variableSlots) { _isScriptBlockForExceptionHandler = true };
}
请注意,当_isScriptBlockForExceptionHandler
设置为true
时,如果发生异常,则在上面的InvokeWithPipe
方法中执行catch块时不会抛出异常:
catch (ReturnException exception2)
{
if (!this._isScriptBlockForExceptionHandler)
{
ParseTreeNode.AppendResult(contextFromTLS, exception2.Argument, null, ref resultList);
}
else
{
exception = exception2;
}
}
AppendResult
方法的作用对我来说并不清楚,但我发现this:
调用AppendResult方法基本上调用了getter 返回的对象的公共属性检索值 将被写入输出控制台。