为什么本地捕获的计时器不会超出范围

本文关键字:范围 计时器 为什么 | 更新日期: 2023-09-27 18:15:28

可能重复:
计时器、事件和垃圾收集:我是不是遗漏了什么?

private void TrayForm_Load(object sender, EventArgs e)
{
    System.Timers.Timer HideMeTimer = new System.Timers.Timer(2500);
    HideMeTimer.Elapsed +=  
        delegate(object sender2, System.Timers.ElapsedEventArgs e2)
        {
            this.Invoke(new Action(somestuff));
        };
        HideMeTimer.Start();
        GC.Collect();
}

有人能告诉我编纂者将如何翻译这个吗?或者很好地解释为什么加载事件后计时器一直在滴答作响。

(这不是最后一次引用变量时的规则,GC有时会杀死物体!(

为什么本地捕获的计时器不会超出范围

您需要了解System.Timers.Timer在幕后做什么。它是System.Threading.Timer类的包装器。当计时器启动时,它会创建一个新的System.Threading.Timer实例,并在System.Timers.Timer实例中向其传递回调方法。只要计时器保持启用状态,系统就会引用此回调委托。

我们还知道,委托保留对包含目标方法的类的实例的引用。这就是为什么System.Timers.Timer实例没有被收集并且不会自动停止的原因。删除Elapsed事件处理程序不会解决此问题,因为委托仅持有对TrayForm实例的引用。同样,是System.Threading.Timer保持对System.Timers.Timer的引用。整个引用链保持根,因为系统必须引用System.Threading.Timer才能工作。

这是参考链:

System => _TimerCallback => Callback => System.Threading.Timer => Callback => System.Timers.Timer

当你用Reflector或ILSpy跟踪这一点时,你可以看到上面参考链中的"系统"是通过标记为MethodImplOptions.InternalCallTimerBase.AddTimerNative方法发挥作用的,所以我们无法确切地看到参考是如何在这一点以下扎根的。但是,它是根深蒂固的。

如果您通过Enabled = falseStop禁用计时器,则它将处理底层System.Threading.Timer,后者将停止引用System.Timers.Timer