在进行代码更改后,PowerShell ISE有时会出现不可预测的行为

ror*_*.ap 5 powershell powershell-ise powershell-5.0

我正在使用PowerShell ISE(PS版本5.0).如果我运行此代码:

Write-Host "This"
Run Code Online (Sandbox Code Playgroud)

它输出:

This
Run Code Online (Sandbox Code Playgroud)

如果我像这样修改脚本:

Write-Host "That"
Run Code Online (Sandbox Code Playgroud)

它输出:

That
Run Code Online (Sandbox Code Playgroud)

大.正如所料.现在,如果我有这个代码:

$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()
Run Code Online (Sandbox Code Playgroud)

它输出:

Here
Run Code Online (Sandbox Code Playgroud)

如果我改变什么在脚本,例如"Here""There"$Timer.Interval = 3000$Timer.Interval = 4000并运行它,它会做两件意想不到的事情:1),而不是显示为适当的时间期限的形式,它短暂闪烁在屏幕上,和2)它输出原始Here而不是There.如果我关闭ISE并重新打开它,脚本将按预期运行.

到底是怎么回事?

mkl*_*nt0 2

长话短说:博士

  • 定时器实例是在会话范围内创建的,

    • 无论您是否在 ISE 中运行脚本,
    • 以及引用它的任何变量是否在范围内。
  • 始终处理计时器(或至少禁用它)以防止它生成更多事件。

  • 一般来说,尽管这不是问题的原因,但请注意,在 ISE 中运行脚本会隐式点源,以便重复执行在同一范围内运行,并且先前执行的变量值会残留,这可能会导致到意想不到的行为。


您的代码永远不会处理(或禁用)计时器,因此:

  • 在整个会话期间保持活动状态,无论变量是否引用它

  • 持续产生事件,

  • 但它们只会在显示表单触发

这解释了您的症状:一旦您再次显示表单,排队的原始事件就会立即触发。

解决方案是在计时器完成其职责并触发事件(一次)后将其处置:

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.
Run Code Online (Sandbox Code Playgroud)

即使使用上述 ISE 的隐式源行为,重复调用此代码也能按预期工作。