是否有任何解释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
}
}
答案 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),你很快就会看到它。