我正在使用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.)输出了原始的HereThere。如果我关闭ISE并重新打开它,脚本将按预期运行。

到底是怎么回事?

最佳答案

tl;博士:

  • 计时器实例是在 session 范围中创建的,
  • 是否在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 - 更改代码后,PowerShell ISE有时会出现无法预期的行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44308958/

    10-10 11:58