2010-03-10 58 views
6

新封考慮以下代碼:上腳本塊

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

如果你指定你所期望的結果,什麼導致你有這將有助於。 – Richard 2010-03-10 09:58:26

+0

添加輸出,所以我希望它很清楚.. – stej 2010-03-10 10:21:23

+0

它看起來像一個錯誤,或者至少我們應該有一種方法來配置它。我發現它已經提交: https://connect.microsoft.com/PowerShell/feedback/details/541754/getnewclosure-doesnt-work-on-register-objectevent# – 2010-05-04 11:33:41

回答

2

作業被執行在一個動態模塊中;模塊已隔離sessionstate,並共享全局變量。 PowerShell閉包只能在同一個sessionstate/scope鏈中工作。煩人,是的。

-Oisin

p.s.我說的「工作」,因爲事件處理程序是有效的地方工作,沒有比腳本不同的是與啓動工作(本地計算機只,含蓄,不使用本地主機 - 計算機)

+0

有道理,接受。你是如何找到有關工作和事件處理程序的信息的?其他來源比反射? :) – stej 2010-06-30 05:56:57

+1

不,我沒有源代碼。只有微軟員工纔有。事件處理程序是作業,因爲get-job會返回它們。 – x0n 2010-06-30 15:31:43

0

我認爲你正在做出不成立的假設。 PSH被解釋,所以當一個代碼塊被創建時它只是保存源代碼。在稍後評估它使用的任何變量時,將以普通PSH方式查找:首先在當前範圍內,然後在每個外部範圍內查找,直到找到具有匹配名稱的變量。

當定時器觸發它的事件,則執行代碼塊,因此查找$i。這是在外部範圍發現的2

的值。在第二種情況下,如果只是直接使用碼塊(刪除調用GetNewClosure),那麼第二執行給出2.

+0

這就是我想要的 - 在第二個例子中,我想得到1,而不是2.它在那裏工作,但不在第一個例子中。 – stej 2010-03-10 10:25:59

+0

GetNewClosure應該改變你在第一段中提到的行爲。 – Segfault 2010-03-10 10:28:43

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