c# - InvalidOperationException:集合已修改;指的是哪个集合?

标签 c# .net multithreading invoke invalidoperationexception

我经常发现它并没有真正指定到底是什么集合导致了这种类型的异常。这是真的还是应该很明显?也许我只是不明白如何正确解释异常消息..

我特别想知道这个。它所指的集合是什么?

事件委托(delegate)的参数很简单(对象发送者),引发的事件传递空参数。尽管引发事件的类本身继承了一个列表:

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() 通常是一个错误。

关于c# - InvalidOperationException:集合已修改;指的是哪个集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14470078/

相关文章:

c# - 浏览器不会在 IIS 8 本地 Web 服务器上显示 Crystal 报表

c# - 我应该将每个类放在单独的文件中吗?

c# - 在 C# XML 中解析 XML 以获取特定内容

c# - 如何在 .net core 上配置 AddAuthorization 以允许多个 token 提供者的角色?

java - 并发解谜: Java Concurrency - Cyclicbarrier. 正确用法?

Java:使用 ExecutorService 实现并发

.net - 如何编写生产者-消费者问题解决方案的测试?

c# - ASP.NET 4.0 单选按钮选中更改事件仅触发一次

c# - 如何在C#中编写sql语句来连接数据

c# - 在 C# 中模拟打开 Excel