System.Windows.Forms.Timer - NullReferenceException

时间:2012-07-04 15:25:26

标签: c#

是否有任何解释NullReference异常,今天在一台机器上发生。我不能在我的电脑上重现它....

class Test
{
  Timer timer_;
  public void Init()
  {
    timer_ = new Timer();
    timer_.Interval = 10000;
    timer_.Tick += OnTimerTick;
    timer_.Start();
  }

  private void OnTimerTick(object sender, EventArgs e)
  {
    timer_.Stop();
    timer_ = null; <--- Null Ref occurs
  }
}

基于Mark Hall和Rich Okelly的精彩建议的解决方案

private void OnTimerTick(object sender, EventArgs e)
{
    var localTimer = Interlocked.Exchange(ref timer_, null);
    if (localTimer != null)
    {
        localTimer.Stop();
        localTimer.Tick -= OnTimerTick;
        localTimer.Dispose();

        // doing staff
    }
}

3 个答案:

答案 0 :(得分:3)

在将计时器设置为null之前,请尝试删除OnTimerTick事件。当你将它设置为null时,这将阻止它被引发,但是由于你创建了一个不太可能的10秒单击,尝试在将它设置为null之前处理你的计时器;

private void OnTimerTick(object sender, EventArgs e) 
{ 
    timer_.Stop(); 
    timer_.Tick -= OnTimerTick;
    timer_.Dispose();
    timer_ = null; 
}

答案 1 :(得分:2)

我认为空引用异常实际上出现在上面的行:timer_.Stop()

发生了什么事情是Tick事件被引发并且另一个被调度,计时器被停止并且由于第一个Tick事件而被设置为null。然后第二个Tick事件尝试在Timer上调用Stop,现在为null。

您可以使用Interlocked方法解决此问题:

private void OnTimerTick(object sender, EventArgs e)
{
  var localTimer= Interlocked.Exchange(ref timer_, null);
  if (localTimer != null) 
  {
     localTimer.Stop();
  }
}

答案 2 :(得分:0)

你说你正在使用System.Windows.Forms.Timer,文档说:

  

此   Windows计时器专为UI的单线程环境而设计   线程用于执行处理。它需要用户代码   有一个UI消息泵可用,并始终使用相同的操作   线程,或将调用封送到另一个线程。

因此不需要使用Interlocked.Exchange,这不是并发问题。

您可以尝试以下代码:

  public void Init()       
  {       
    if (timer_ != null)
      throw new InvalidOperationException("Already initialized!");
    timer_ = new Timer();       
    timer_.Interval = 10000;       
    timer_.Tick += OnTimerTick;       
    timer_.Start();       
  }       


  private void OnTimerTick(object sender, EventArgs e) 
  { 
    if (timer_ != null)
    {
      timer_.Stop();
      timer_.Dispose();
      timer_ = null;

      // Your code
    }
  } 

这样,在第一个tick tick_将被停止并设置为null。如果有任何挂起的Tick,由于(timer_!= null),它将被忽略。

此外,如果在计时器运行时调用Init()(可能是一个bug),你很快就会看到它。