c# – 奇怪的“枚举器被实例化后的集合被修改”异常

前端之家收集整理的这篇文章主要介绍了c# – 奇怪的“枚举器被实例化后的集合被修改”异常前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
也许有人可以指出我的方向是正确的,因为我完全是这样的.

我有一个函数,只需打印出一个LinkedList的类:

LinkedList<Component> components = new LinkedList<Component>();
    ...
    private void PrintComponentList()
    {
        Console.WriteLine("---Component List: " + components.Count + " entries---");
        foreach (Component c in components)
        {
            Console.WriteLine(c);
        }
        Console.WriteLine("------");
    }

Component对象实际上有一个自定义的ToString()调用

int Id;
    ...
    public override String ToString()
    {
        return GetType() + ": " + Id;
    }

功能通常工作正常 – 但是我遇到的问题是,当它建立到列表中大约30个条目时,PrintcomplentList foreach语句返回一个InvalidOperationException:在枚举器被实例化之后,集合被修改.

现在,您可以看到我没有修改for循环中的代码,而且我没有明确创建任何线程,尽管这在XNA环境中(如果重要).应该注意的是,打印输出是足够频繁的,以至于控制台输出整体上减慢了程序的速度.

我完全陷入困境,有没有人遇到这个?

解决方法

我怀疑开始寻找的地方将在您操纵列表的任何地方 – 即插入/删除/重新分配项目.我的怀疑是,在某个地方将会有一个回调/甚至处理程序异步地被触发(也许作为XNA绘画等循环的一部分),并且正在编辑列表 – 基本上是将这个问题作为竞争条件.

要检查是否是这种情况,请在操作列表的地方放置一些调试/跟踪输出,并查看是否有(特别是在异常之前)与控制台输出同时运行操作代码

private void SomeCallback()
{
   Console.WriteLine("---Adding foo"); // temp investigation code; remove
   components.AddLast(foo);
   Console.WriteLine("---Added foo"); // temp investigation code; remove
}

不幸的是,这样的事情往往是调试的痛苦,因为改变代码进行调查往往会改变问题(一个Heisenbug).

一个答案是同步访问;即在编辑列表的所有地方,请使用围绕整个操作的锁定:

LinkedList<Component> components = new LinkedList<Component>();
readonly object syncLock = new object();
...
private void PrintComponentList()
{
    lock(syncLock)
    { // take lock before first use (.Count),covering the foreach
        Console.WriteLine("---Component List: " + components.Count
              + " entries---");
        foreach (Component c in components)
        {
           Console.WriteLine(c);
        }
        Console.WriteLine("------");
    } // release lock
}

在你的回调(或任何)

private void SomeCallback()
{
   lock(syncLock)
   {
       components.AddLast(foo);
   }
}

特别是,“完整操作”可能包括

>检查计数和foreach / for
检查是否存在并插入/删除
>等

(即不是个人/离散操作 – 但是工作单位)

猜你在找的C#相关文章