如何在调用方的上下文中调用脚本块?



考虑以下调用站点:

$modifiedLocal = 'original local value'
'input object' | SomeScriptblockInvoker {
$modifiedLocal = 'modified local value'
[pscustomobject] @{
Local = $local
DollarBar = $_
}
}
$modifiedLocal

我想实施SomeScriptblockInvoker以便

  1. 它在模块中定义,并且
  2. 脚本块在调用方的上下文中调用。

调用站点上的函数输出如下所示:

Local DollarBar   
----- ---------   
local input object
modified local value

PowerShell似乎有能力做到这一点。 例如,用ForEach-Object替换SomeScriptblockInvoker可以产生所需的输出。

我使用以下定义接近:

New-Module m {
function SomeScriptblockInvoker {
param
(
[Parameter(Position = 1)]
[scriptblock]
$Scriptblock,
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
$InputObject | . $Scriptblock
}
}
} |
Import-Module

使用该定义的调用站点的输出如下所示:

Local DollarBar
----- ---------
local          
modified local value

请注意,DollarBar在应该input object时为空。

(纠缠测试的要点,以检查正确的行为)

一般来说,你不能。 脚本块的调用方无法控制与该脚本块关联的 SessionState,并且 SessionState 确定(部分)执行脚本块的上下文(有关详细信息,请参阅"范围"部分)。 根据定义脚本块的位置,其 SessionState 可能与调用方的上下文匹配,但可能不匹配。

范围

关于执行脚本块的上下文,有两个相关的注意事项:

  1. 与脚本块关联的会话状态。
  2. 调用方法是否将作用域添加到 SessionState 的作用域堆栈。

这是对它如何工作的很好的解释。

$_自动变量

$_包含管道中的当前对象。 提供给%的脚本块与.&提供的脚本块的解释不同:

  • 'input_object' | % {$_}-$_的值'input_object',因为脚本块绑定到%-Process参数。 该脚本块为管道中的每个对象执行一次。
  • 'input_object' | . {process{$_}}'input_object' | & {process{$_}}-$_的值'input_object',因为脚本块中的$_位于process{}块内,该块对管道中的每个对象执行一次。

请注意,在 OP 中,当使用.调用脚本块时,$_为空。 这是因为脚本块不包含process{}块。 脚本块中的每个语句都是脚本块end{}块的隐式部分。 运行end{}块时,管道中不再有任何对象,$_为 null。

.vs&vs%

.&%分别使用脚本块的 SessionState 调用脚本块,但根据下表存在一些差异:

+---+-----------------+-----------+-------------------+----------------------+
|   |      Name       |    Kind   |  interprets {} as |  adds scope to stack |
+---+-----------------+-----------+-------------------+----------------------+
| % |  ForEach-Object |  Command  |  Process block    |  No                  |
| . |  dot-source     |  Operator |  scriptblock      |  No                  |
| & |  call           |  Operator |  scriptblock      |  Yes                 |
+---+-----------------+-----------+-------------------+----------------------+
  • %命令具有对应于Begin{}End{}块的其他参数。
  • 要使脚本块进行的变量赋值对与脚本块关联的 SessionState 产生副作用,请使用不向堆栈添加作用域的调用方法。 否则,变量赋值只会影响新创建的作用域,并在脚本块完成执行后消失。

最可行的选择

在 OP 中通过测试的两个最可行的选项如下。 请注意,两者都不会严格在调用方的上下文中调用脚本块,而是在使用与脚本块关联的 SessionState 的上下文中调用脚本块。

选项 1

更改调用站点,以便脚本块包含process{}

$modifiedLocal = 'original local value'
'input object' | SomeScriptblockInvoker {
process {
$modifiedLocal = 'modified local value'
[pscustomobject] @{
Local = $local
DollarBar = $_
}
}
}
$modifiedLocal

并在 OP 中使用SomeScriptblockInvoker调用脚本块。

选项 2

按照 PetSeral 的建议使用%调用脚本块。

相关内容

  • 没有找到相关文章

最新更新