scriptblock上的新闭包

时间:2010-03-10 09:52:33

标签: events powershell closures

考虑以下代码:

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 个答案:

答案 0 :(得分:2)

作业在动态模块中执行;模块具有隔离的会话状态,并共享对全局变量的访问。 PowerShell闭包只能在同一个sessionstate / scope链中工作。很烦人,是的。

-Oisin

P.S。我说“作业”,因为事件处理程序实际上是本地作业,与使用start-job运行的脚本没有什么不同(仅限本地计算机,隐式,不使用-computer localhost)

答案 1 :(得分:0)

我认为你做的假设不成立。 PSH被解释,因此当创建代码块时,它只保存源代码。稍后评估它使用的任何变量将以正常的PSH方式查找:首先在当前范围内,然后在每个外部范围内,直到找到具有匹配名称的变量。

当计时器触发其事件时,它会执行代码块,从而查找$i。在外部范围中找到的值为2。

在第二种情况下,如果您只是直接使用代码块(删除对GetNewClosure的调用),则第二次执行会给出2。

答案 2 :(得分:0)

在这种情况下使用全局变量:

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