我无法找到这个错误的根源,因为当附加调试器时,它似乎没有发生。

修改集合;枚举操作可能无法执行

下面是代码。

这是Windows服务中的WCF服务器。只要有数据事件,服务就会调用NotifySubscribers()方法(随机间隔,但不经常——大约每天800次)。

When a Windows Forms client subscribes, the subscriber ID is added to the subscribers dictionary, and when the client unsubscribes, it is deleted from the dictionary. The error happens when (or after) a client unsubscribes. It appears that the next time the NotifySubscribers() method is called, the foreach() loop fails with the error in the subject line. The method writes the error into the application log as shown in the code below. When a debugger is attached and a client unsubscribes, the code executes fine.

您认为这段代码有问题吗?我需要使字典线程安全吗?

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class SubscriptionServer : ISubscriptionServer
{
    private static IDictionary<Guid, Subscriber> subscribers;

    public SubscriptionServer()
    {            
        subscribers = new Dictionary<Guid, Subscriber>();
    }

    public void NotifySubscribers(DataRecord sr)
    {
        foreach(Subscriber s in subscribers.Values)
        {
            try
            {
                s.Callback.SignalData(sr);
            }
            catch (Exception e)
            {
                DCS.WriteToApplicationLog(e.Message, 
                  System.Diagnostics.EventLogEntryType.Error);

                UnsubscribeEvent(s.ClientId);
            }
        }
    }
    
    public Guid SubscribeEvent(string clientDescription)
    {
        Subscriber subscriber = new Subscriber();
        subscriber.Callback = OperationContext.Current.
                GetCallbackChannel<IDCSCallback>();

        subscribers.Add(subscriber.ClientId, subscriber);
        
        return subscriber.ClientId;
    }

    public void UnsubscribeEvent(Guid clientId)
    {
        try
        {
            subscribers.Remove(clientId);
        }
        catch(Exception e)
        {
            System.Diagnostics.Debug.WriteLine("Unsubscribe Error " + 
                    e.Message);
        }
    }
}

当前回答

为什么会出现这个错误?

一般来说。net集合不支持同时被枚举和修改。如果在枚举期间试图修改集合列表,则会引发异常。所以这个错误背后的问题是,当我们循环遍历列表/字典时,我们不能修改它。

其中一个解决方案

如果使用字典的键列表迭代字典,则可以在遍历键集合和时同时修改字典对象 不是字典(以及迭代它的键集合)。

例子

//get key collection from dictionary into a list to loop through
List<int> keys = new List<int>(Dictionary.Keys);

// iterating key collection using a simple for-each loop
foreach (int key in keys)
{
  // Now we can perform any modification with values of the dictionary.
  Dictionary[key] = Dictionary[key] - 1;
}

这里有一篇关于这个解决方案的博客文章。

并深入研究StackOverflow:为什么会发生此错误?

其他回答

好的,帮助我的是向后迭代。我试图从列表中删除一个条目,但向上迭代,它搞砸了循环,因为该条目不再存在了:

for (int x = myList.Count - 1; x > -1; x--)
{
    myList.RemoveAt(x);
}

为什么会出现这个错误?

一般来说。net集合不支持同时被枚举和修改。如果在枚举期间试图修改集合列表,则会引发异常。所以这个错误背后的问题是,当我们循环遍历列表/字典时,我们不能修改它。

其中一个解决方案

如果使用字典的键列表迭代字典,则可以在遍历键集合和时同时修改字典对象 不是字典(以及迭代它的键集合)。

例子

//get key collection from dictionary into a list to loop through
List<int> keys = new List<int>(Dictionary.Keys);

// iterating key collection using a simple for-each loop
foreach (int key in keys)
{
  // Now we can perform any modification with values of the dictionary.
  Dictionary[key] = Dictionary[key] - 1;
}

这里有一篇关于这个解决方案的博客文章。

并深入研究StackOverflow:为什么会发生此错误?

我也有同样的问题,当我使用for循环而不是foreach时,它得到了解决。

// foreach (var item in itemsToBeLast)
for (int i = 0; i < itemsToBeLast.Count; i++)
{
    var matchingItem = itemsToBeLast.FirstOrDefault(item => item.Detach);

   if (matchingItem != null)
   {
      itemsToBeLast.Remove(matchingItem);
      continue;
   }
   allItems.Add(itemsToBeLast[i]);// (attachDetachItem);
}

InvalidOperationException - 发生了InvalidOperationException。它报告foreach循环中的“集合被修改”

使用break语句,一旦对象被移除。

ex:

ArrayList list = new ArrayList(); 

foreach (var item in list)
{
    if(condition)
    {
        list.remove(item);
        break;
    }
}

可以将订阅者字典对象复制到相同类型的临时字典对象,然后使用foreach循环迭代该临时字典对象。