Новое закрытие скриптового блока - PullRequest
6 голосов
/ 10 марта 2010

Рассмотрим этот код:

PS> $timer = New-Object Timers.Timer
PS> $timer.Interval = 1000
PS> $i = 1;
PS> Register-ObjectEvent $timer Elapsed -Action { write-host 'i: ' $i }.GetNewClosure()
PS> $timer.Enabled = 1
i:  1
i:  1
i:  1
 ...
# wait a couple of seconds and change $i
PS> $i = 2
i:  2
i:  2
i:  2

Я предполагал, что при создании нового замыкания ({ write-host 'i: ' $i }.GetNewClosure()) значение $i будет привязано к этому замыканию.Но не в этом случае.Когда я меняю значение, write-host принимает новое значение.

С другой стороны, это работает:

PS> $i = 1;
PS> $action = { write-host 'i: ' $i }.GetNewClosure()
PS> &$action
i:  1
PS> $i = 2
PS> &$action
i:  1

Почему оно не работает с Register-ObjectEvent?

Ответы [ 3 ]

2 голосов
/ 30 июня 2010

Задания выполняются в динамическом модуле; модули имеют изолированное состояние сеанса и совместно используют доступ к глобальным переменным. Закрытия PowerShell работают только в одной и той же цепочке состояния сеанса / области. Раздражает, да.

-Oisin

p.s. Я говорю «задания», потому что обработчики событий фактически являются локальными заданиями, не отличающимися от сценариев, запускаемых с помощью start-job (только локальный компьютер, неявный, без использования -computer localhost)

0 голосов
/ 07 февраля 2014

Используйте глобальные переменные в этом случае:

PS> $global:i = 1
PS> $timer = New-Object Timers.Timer
PS> $timer.Interval = 1000
PS> Register-ObjectEvent $timer Elapsed -Action { write-host 'i: ' $global:i }.GetNewClosure()
PS> $timer.Enabled = 1
i:  1
i:  1
i:  1

PS> Set-Variable -Name i -Value 2 -Scope Global

i:  2
i:  2
i:  2

Источник:

http://stackoverflow.com/q/12535419/1287856
0 голосов
/ 10 марта 2010

Я думаю, что вы делаете предположения, которые не верны. PSH интерпретируется, поэтому, когда создается блок кода, он просто содержит исходный код. Когда он позднее оценивается, любые используемые им переменные будут просматриваться обычным образом PSH: сначала в текущей области, а затем в каждой внешней области, пока не будет найдена переменная с соответствующим именем.

Когда таймер запускает свое событие, он выполняет блок кода и, таким образом, ищет $i. Который находится во внешней области видимости со значением 2.

Во втором случае, если вы просто используете блок кода напрямую (удалите вызов GetNewClosure), то при втором выполнении вы получите 2.

...