bre*_*dog 2 .net c# multithreading invoke invalidoperationexception
我经常发现它没有真正指定究竟是什么样的集合导致了这种类型的异常.这是真的还是应该是显而易见的?也许我只是不明白如何正确解释异常消息..
我特别想知道这个.它指的是什么系列?
事件委托的参数只是(对象发送者),并且引发的事件传递null参数.虽然引发事件的类本身继承了一个列表:
public class TimeSerie : List<BarData>
Run Code Online (Sandbox Code Playgroud)
这里是否清楚"集合"是指引发事件的对象,还是它可以是另一个对象?可以这么说,一个动态改变的方法的事件处理程序的集合?或者会创建一个不同的例外?
************** 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)
Run Code Online (Sandbox Code Playgroud)
UserControl中发生异常:
public class SomeUserControl
private void InvokeOnUpdate(object sender)
{
this.Invoke(new GenericInvoker(Method)); // << Exception here!
}
private void Method() {...}
Run Code Online (Sandbox Code Playgroud)
编辑: 添加了一些代码.有点简化,但认为它包括相关位.
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;
}
Run Code Online (Sandbox Code Playgroud)
是的,当您使用Control.Invoke()时,很难诊断异常的原因.问题是它在UI线程上发生异常并在工作线程中重新抛出异常时捕获异常.必然如此,您的工作线程需要知道Invoke()的返回值不可用.不可避免的副作用是你失去了圣堆痕迹,告诉你它在哪里爆炸以及它是如何到达那里的.
如果您在连接调试器时可以重新解决问题,请使用Debug + Exceptions,勾选CLR Exceptions的Thrown复选框.抛出异常时调试器停止,为您提供良好的语句位置和调用堆栈.
如果没有,那么请考虑使用Control.BeginInvoke().这是Invoke()的即发即弃版本,因此如果调用的方法抛出,那么将在UI线程上引发该异常,并且您将获得准确的堆栈跟踪.
通常,您总是希望使用BeginInvoke().它不会导致工作线程停止,它避免了许多死锁情况并提供了良好的异常反馈.使用Invoke()通常是一个错误.
| 归档时间: |
|
| 查看次数: |
1132 次 |
| 最近记录: |