为什么add_EventName不能与Timer一起使用?

Fro*_* F. 10 powershell powershell-2.0 powershell-3.0

在PowerShell中,您可以使用add_NameOfEvent({scriptblock})对象的-method 订阅事件.这适用于像按钮等的Form对象.但是,当我尝试使用它时System.Timers.Timer它不起作用.这是为什么?样品:

$timer1 = New-Object System.Timers.Timer
$timer1.Interval = 2000
$timer1.add_Elapsed({ Write-Host "Timer1 tick" })

$timer2 = New-Object System.Timers.Timer
$timer2.Interval = 2000
Register-ObjectEvent -InputObject $timer2 -EventName Elapsed -Action { Write-Host "Timer2 tick" }

$timer1.Start()
$timer2.Start()
Run Code Online (Sandbox Code Playgroud)

$timer2将工作正常,但$timer1永远不会写入控制台.Timer与ex有什么不同.一个表单组件(该add_...方法的工作原理)?是否Timer在单独的线程中运行并因此写入"隐藏"控制台?

证明该方法适用于那些不熟悉它的人的表单组件:

PS > Add-Type -AssemblyName System.Windows.Forms
PS > $b = New-Object System.Windows.Forms.Button
PS > $b.add_click({ Write-Host "button" })
#Get-EventSubscriber won't show this event, but it's added
PS > $b.PerformClick()
button
Run Code Online (Sandbox Code Playgroud)

CB.*_*CB. 6

如果您尝试此代码:

$w = new-object 'System.Windows.Forms.Form'
$timer1 = New-Object System.Timers.Timer
$timer1.Interval = 2000
$timer1.add_Elapsed({ Write-Host "Timer1 tick" })
$timer1.SynchronizingObject = $w
$timer1.Start()
$w.ShowDialog()
Run Code Online (Sandbox Code Playgroud)

您将看到预期的行为,因为System.Timers.Timer可以与窗口表单同步(如在ac#代码中).

powershell控制台中的问题是计时器是在不同的线程中创建的,无法与控制台同步,因为它没有公开ISynchronizeInvoke表示用于编组间隔时间内发出的事件处理程序调用的对象的接口.

如果SynchronizingObjectnull,处理该事件经过的调用方法从系统线程池中的线程.

IMO在场景后面Register-ObjectEvent创建一个系统线程池来完成事件处理程序调用.

我无法用手重新创建什么Register-ObjectEvent ,但我认为可以使用一些c#/ Pinvoke代码.