我试图弄清楚ScriptBlock.GetNewClosure()的工作方式。基于this线程(请参阅Stej的答案),我有以下代码:

$i = 1
$block1 =
{
    $i
}

$i = 2
$block2 =
{
    $i
}

$i = 3
$block3 =
{
    $i
}


& $block1
& $block2
& $block3

输出为:
3
3
3

这是可以预期的,因为执行ScriptBlocks时会使用当前的$ i值。可以使用GetNewClosure()进行更改:
$i = 1
$block1 =
{
    $i
}.GetNewClosure()

$i = 2
$block2 =
{
    $i
}.GetNewClosure()

$i = 3
$block3 =
{
    $i
}.GetNewClosure()


& $block1
& $block2
& $block3

这次的输出是:
1
2
3

这很好,但是当我尝试将ScriptBlocks标记为作业时:
$i = 1
$block1 =
{
    $i
}.GetNewClosure()

$i = 2
$block2 =
{
    $i
}.GetNewClosure()

$i = 3
$block3 =
{
    $i
}.GetNewClosure()


$job1 = Start-Job $block1
$job1 | Wait-Job
$job1 | Receive-Job

$job2 = Start-Job $block2
$job2 | Wait-Job
$job2 | Receive-Job

$job3 = Start-Job $block3
$job3 | Wait-Job
$job3 | Receive-Job

没有输出。在寻找答案时,我找到了this线程,其中x0n表示作业是在动态模块中执行的。模块具有隔离的 session 状态,并共享对全局变量的访问。 PowerShell闭包仅在同一 session 状态/作用域链中起作用

这是否意味着无法从作业中访问$ i?当我测试其值时:
$i = 1
$block1 =
{
    $i -eq $null
}.GetNewClosure()

$i = 2
$block2 =
{
    $i -eq $null
}.GetNewClosure()

$i = 3
$block3 =
{
    $i -eq $null
}.GetNewClosure()


$job1 = Start-Job $block1
$job1 | Wait-Job
$job1 | Receive-Job

$job2 = Start-Job $block2
$job2 | Wait-Job
$job2 | Receive-Job

$job3 = Start-Job $block3
$job3 | Wait-Job
$job3 | Receive-Job

$等于null。

最佳答案

是的,这意味着作业无法以这种方式访问​​$i。很遗憾。因此,使用另一种方式:例如,将脚本块中的param作为作业调用,并将ArgumentList参数设置为Start-Job:

$i = 42
$block1 =
{
    param($i)
    $i * 2
}

$job1 = Start-Job $block1 -ArgumentList $i
$job1 | Wait-Job | Receive-Job

输出:
84

P.S.据报道GetNewClosure也不能与Register-ObjectEvent一起使用:
https://connect.microsoft.com/PowerShell/feedback/details/541754/getnewclosure-doesnt-work-on-register-objectevent

关于powershell - ScriptBlock.GetNewClosure()行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4058721/

10-15 19:17