更改代码后,PowerShell ISE 有时会出现不可预测的行为
The PowerShell ISE sometimes behaves unpredictably after code changes are made
我正在使用 PowerShell ISE(PS 5.0 版)。如果我 运行 这个代码:
Write-Host "This"
它输出:
This
如果我这样修改脚本:
Write-Host "That"
它输出:
That
太棒了。不出所料。现在,如果我有这个代码:
$Form = New-Object System.Windows.Forms.Form
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Add_Tick(
{
&{
Write-Output "Here"
$Form.Close()} | Write-Host
})
$Timer.Interval = 3000
$Timer.start()
$result = $Form.ShowDialog()
它输出:
Here
如果我在脚本中更改 任何内容,例如"Here"
到 "There"
或 $Timer.Interval = 3000
到 $Timer.Interval = 4000
和 运行 它做了两件意想不到的事情:1.) 而不是在适当的持续时间内显示表格时间,它会在屏幕上短暂闪烁,并且 2.) 它会输出原始的 Here
而不是 There
。如果我关闭 ISE 并重新打开它,脚本 运行s 会按预期运行。
这是怎么回事?
我认为这与脚本结束后 ISE 中的变量如何仍在内存中有关。如果您添加
$Timer.Stop()
到脚本的最后一行,然后关闭并重新打开 ISE 它将工作。
tl;dr:
计时器实例在会话范围、
中创建
- 您是否运行您的脚本在 ISE 中,
- 以及引用它的任何变量是否在范围内。
始终处理计时器(或至少禁用它)以防止它产生更多事件。
通常 - 尽管这不是手头问题的原因 - 请注意运行在ISE中设置一个脚本隐式点源它,以便在中重复执行运行相同 作用域,具有来自先前值的变量值挥之不去,这可能会导致意外行为。
您的代码从不处理(或禁用)计时器,因此:
在整个 session 期间保持活动状态,无论变量是否引用它
继续生成事件,
但它们仅在显示 表单时 触发 。
这解释了您的症状:排队,原始事件在您显示表单后立即立即再次.
解决方案是在计时器完成任务并触发事件(一次)后处理掉它:
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object System.Windows.Forms.Form
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Add_Tick({
& {
Write-Output "Here"
$Form.Close()
} | Write-Host
})
$Timer.Interval = 3000
$Timer.Start()
$result = $Form.ShowDialog()
$Timer.Dispose() # IMPORTANT: Dispose of the timer so it won't generate more events.
即使使用上述 ISE 的隐式采购行为,重复调用此代码也能按预期工作。
我正在使用 PowerShell ISE(PS 5.0 版)。如果我 运行 这个代码:
Write-Host "This"
它输出:
This
如果我这样修改脚本:
Write-Host "That"
它输出:
That
太棒了。不出所料。现在,如果我有这个代码:
$Form = New-Object System.Windows.Forms.Form
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Add_Tick(
{
&{
Write-Output "Here"
$Form.Close()} | Write-Host
})
$Timer.Interval = 3000
$Timer.start()
$result = $Form.ShowDialog()
它输出:
Here
如果我在脚本中更改 任何内容,例如"Here"
到 "There"
或 $Timer.Interval = 3000
到 $Timer.Interval = 4000
和 运行 它做了两件意想不到的事情:1.) 而不是在适当的持续时间内显示表格时间,它会在屏幕上短暂闪烁,并且 2.) 它会输出原始的 Here
而不是 There
。如果我关闭 ISE 并重新打开它,脚本 运行s 会按预期运行。
这是怎么回事?
我认为这与脚本结束后 ISE 中的变量如何仍在内存中有关。如果您添加
$Timer.Stop()
到脚本的最后一行,然后关闭并重新打开 ISE 它将工作。
tl;dr:
计时器实例在会话范围、
中创建- 您是否运行您的脚本在 ISE 中,
- 以及引用它的任何变量是否在范围内。
始终处理计时器(或至少禁用它)以防止它产生更多事件。
通常 - 尽管这不是手头问题的原因 - 请注意运行在ISE中设置一个脚本隐式点源它,以便在中重复执行运行相同 作用域,具有来自先前值的变量值挥之不去,这可能会导致意外行为。
您的代码从不处理(或禁用)计时器,因此:
在整个 session 期间保持活动状态,无论变量是否引用它
继续生成事件,
但它们仅在显示 表单时 触发 。
这解释了您的症状:排队,原始事件在您显示表单后立即立即再次.
解决方案是在计时器完成任务并触发事件(一次)后处理掉它:
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object System.Windows.Forms.Form
$Timer = New-Object System.Windows.Forms.Timer
$Timer.Add_Tick({
& {
Write-Output "Here"
$Form.Close()
} | Write-Host
})
$Timer.Interval = 3000
$Timer.Start()
$result = $Form.ShowDialog()
$Timer.Dispose() # IMPORTANT: Dispose of the timer so it won't generate more events.
即使使用上述 ISE 的隐式采购行为,重复调用此代码也能按预期工作。