2010-10-30 6 views
8

Estoy intentando averiguar cómo funciona ScriptBlock.GetNewClosure(). Sobre la base de this hilo (véase la respuesta de Stej) Tengo este código:ScriptBlock.GetNewClosure() Comportamiento

$i = 1 
$block1 = 
{ 
    $i 
} 

$i = 2 
$block2 = 
{ 
    $i 
} 

$i = 3 
$block3 = 
{ 
    $i 
} 


& $block1 
& $block2 
& $block3 

La salida es:

3 
3 
3 

que se espera, ya que cuando se ejecutan los ScriptBlocks se utiliza el valor de $ i actual. Esto se puede cambiar usando GetNewClosure():

$i = 1 
$block1 = 
{ 
    $i 
}.GetNewClosure() 

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

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


& $block1 
& $block2 
& $block3 

Esta vez la salida es:

1 
2 
3 

Esto es bueno, pero cuando trato de la estrella de la ScriptBlocks como puestos de trabajo:

$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 

No hay salida. Buscando una respuesta, encontré el hilo this, donde x0n dice que las tareas se ejecutan en un módulo dinámico. Los módulos tienen sessionstate aislado y comparten acceso a globales. Los cierres de PowerShell solo funcionan dentro de la misma cadena sessionstate/scope

¿Esto significa que $ i no es accesible desde los trabajos? Cuando pruebo su valor:

$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 

$ es igual a nulo.

Respuesta

6

Sí, significa que $i no es accesible desde los trabajos de esta manera. Desafortunadamente. Por lo tanto, el uso de otra forma: por ejemplo, param en un bloque de script que se invoca como un trabajo y ArgumentList parámetro de Start-Job:

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

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

Salida:

84 

P. S. Se informa que también GetNewClosure no funciona con Register-ObjectEvent: https://connect.microsoft.com/PowerShell/feedback/details/541754/getnewclosure-doesnt-work-on-register-objectevent

+0

Gracias por la respuesta. ¿Este comportamiento está documentado por Microsoft? –

+0

Bueno, yo diría que es una característica legal, pero la documentación al respecto podría ser mejor. Por cierto, en vez de 'param' en un bloque de script, puedes usar' $ args'. –

-1
$i = 1 
$block1 = {"block 1 is $using:i" }.GetNewClosure() 

$i = 2 
$block2 = { "block 2 is $using:i" }.GetNewClosure() 

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

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

http://www.powertheshell.com/closure/