hai*_*yyu 13 c# dispose exception winforms
在我当前的项目中有一个Form类,如下所示:
public partial class FormMain : Form
{
System.Timers.Timer timer;
Point previousLocation;
double distance;
public FormMain()
{
InitializeComponent();
distance = 0;
timer = new System.Timers.Timer(50);
timer.AutoReset = true;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (previousLocation != null)
{
// some code
UpdateDistanceLabel(distance);
UpdateSpeedLabel(v);
}
previousLocation = Cursor.Position;
}
private void UpdateDistanceLabel(double newDistance)
{
if (!lblDistance.IsDisposed && !IsDisposed)
{
Invoke(new Action(() => lblDistance.Text = String.Format("Distance: {0} pixels", newDistance)));
}
}
private void UpdateSpeedLabel(double newSpeed)
{
if (!lblSpeed.IsDisposed && !IsDisposed)
{
Invoke(new Action(() => lblSpeed.Text = String.Format("Speed: {0} pixels per second", newSpeed)));
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我正在使用System.Timers.Timer对象.我知道我可以使用System.Windows.Forms.Timer,但我对我仍然得到标题中显示的异常的原因很感兴趣.它会在UpdateDistanceLabel方法的Invoke调用中抛出.令我困惑的是它说"无法访问处置对象:FormMain",即使我正在检查它是否被处置.所以这不应该发生.我也尝试在FormClosing事件中处理timer对象以及重写Dispose(bool)并将其处理在那里,但遗憾的是两者都没有帮助.此外,异常并不总是被抛出,据说只有在程序退出时计时器发生时才会被抛出.它仍然发生了很多.
我已经看到有关于此的大量线索,但我已经尝试过那里发布的解决方案,其中大多数涉及检查IsDisposed属性 - 这对我不起作用.所以我想我做错了什么.
所以我的问题:为什么上面发布的代码会触发异常,即使我正在检查我访问的对象是否被处理?
sup*_*cat 10
有两种解决方法:要么吞下异常,并诅咒微软没有包括一个TryInvoke和TryBeginInvoke方法,或者使用锁定,以确保不尝试做出Dispose的对象,而它在使用中,并没有尝试使用对象而Dispose为进行中.我认为吞下异常可能更好,但有些人对这些事情有内心反应,并且使用锁定可以避免首先发生异常.
一个问题是你在调用之前正在检查计时器线程Invoke.存在可能的竞争条件,其中可以在检查之后并且在执行调用的动作之前处理表单.
您应该在方法内部(在您的情况下为lambda表达式)中进行检查Invoke.
另一个可能的问题是您正在访问Cursor.Position计时器线程.我不确定这是否有效 - 我会在主线程上执行此操作.您的代码还包含注释//some code- 因此您可能会省略一些您还需要检查的代码.
总的来说,你可能会更好地使用System.Windows.Forms.Timer.
如果您有兴趣,这是我的异常解决方案:
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
timer.Stop();
Application.DoEvents();
}
Run Code Online (Sandbox Code Playgroud)
没有.DoEvents()的.Stop()是不够的,因为它会在不等待你的线程完成其工作的情况下处理对象.