无效操作异常:集合已修改;指哪个集合
本文关键字:集合 修改 操作 异常 无效 | 更新日期: 2023-09-27 17:55:24
我经常发现并没有真正指定导致此类异常的确切集合。这是真的还是显而易见的?也许我只是不明白如何正确解释异常消息。
具体来说,我想知道这个。它指的是什么集合?
事件委托的参数很简单(对象发送方),引发的事件传递 null 参数。尽管引发事件的类本身继承了一个列表:
public class TimeSerie : List<BarData>
这里是否清楚"集合"是指引发事件的对象,或者它可以是另一个对象?是否可以是动态更改的方法的事件处理程序集合?或者这会创建一个不同的例外吗?
************** Exception Text **************
System.InvalidOperationException:
Collection was modified; enumeration operation may not execute.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.Invoke(Delegate method)
at SomeNameSpace.SomeUserControl.InvokeOnUpdateHistory(Object sender) in D:'SomePath'SomeUserControl.cs:line 5179
at OtherNameSpace.OtherClass.TimeSerie.HistoryUpdateEventHandler.Invoke(Object sender)
用户控件中发生异常:
public class SomeUserControl
private void InvokeOnUpdate(object sender)
{
this.Invoke(new GenericInvoker(Method)); // << Exception here!
}
private void Method() {...}
编辑:添加了一些代码。有点简化,但认为它包括相关位。
private void Method()
{
if (this.instrument == null) return;
UnRegisterTimeSerieHandlers(this.ts);
this.ts = instrument.DataSeries.GetTimeSerieByInterval(interval);
if (ts != null)
{
RegisterTimeseriesHandlers(ts);
ClearAndLoadAllHistory();
}
}
private void UnRegisterTimeSerieHandlers(TimeSerie ts)
{
if (ts != null)
{
ts.TickUpdate -= InvokeUpdateCurrentBar;
ts.NewBarUpdate -= InvokeUpdateNewBar;
ts.HistoryUpdate -= InvokeOnUpdateHistory;
this.ts = null;
}
}
private void RegisterTimeseriesHandlers(TimeSerie ts)
{
ts.TickUpdate += InvokeUpdateCurrentBar;
ts.NewBarUpdate += InvokeUpdateNewBar;
ts.HistoryUpdate += InvokeOnUpdateHistory;
}
是的,当您使用 Control.Invoke() 时,异常的原因可能很难诊断。 问题是,当异常发生在 UI 线程上时,它会捕获异常,并将其重新引发到工作线程中。 因此,您的工作线程需要知道 Invoke() 的返回值不可用。 不可避免的副作用是你失去了神圣堆栈痕迹,它会告诉你它在哪里爆炸以及它是如何到达那里的。
如果在附加了调试器时可以重现问题,请使用"调试 + 异常",勾选"CLR 异常"的"引发"复选框。 当引发异常时,调试器将停止,从而为您提供一个良好的语句位置和要查看的调用堆栈。
如果没有,请考虑改用 Control.BeginInvoke()。 这是 Invoke() 的即发即弃版本,因此如果调用的方法引发,则该异常将在 UI 线程上引发,您将获得准确的堆栈跟踪。
一般来说,你总是希望支持BeginInvoke()。 它不会导致工作线程停止,它避免了许多死锁情况,并提供良好的异常反馈。 使用 Invoke() 通常是一个错误。
您似乎正在使用计时器。也许您正在从计时器回调(另一个线程)更改某些集合(更有可能,集合是 UI 元素的属性),而无需使用Control.Invoke()
调用?