考虑以下代码:
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
?
答案 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