为了账号安全,请及时绑定邮箱和手机立即绑定

集合已被修改;枚举操作可能不会执行。

集合已被修改;枚举操作可能不会执行。

慕斯王 2019-06-03 10:05:46
集合已被修改;枚举操作可能不会执行。我无法找到这个错误的底部,因为当附加调试器时,它似乎不会发生。下面是密码。这是Windows服务中的WCF服务器。每当有数据事件时,服务都会调用NotifySubscriber方法(随机间隔,但不经常-每天大约800次)。当Windows窗体客户端订阅时,订阅者ID将添加到订阅者字典中,而当客户端取消订阅时,它将从字典中删除。当客户端取消订阅时(或之后)发生错误。似乎下一次调用NotifySubscriber()方法时,foreach()循环会失败,主题行中的错误会导致失败。该方法将错误写入应用程序日志,如下代码所示。当附加调试器和客户端取消订阅时,代码执行良好。你看到这个代码有问题了吗?我需要让字典线程安全吗?[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);         }     }}
查看完整描述

4 回答

?
神不在的星期二

TA贡献1963条经验 获得超6个赞

可能发生的是SignalData在循环期间间接地更改订阅者字典并导致消息。您可以通过更改

foreach(Subscriber s in subscribers.Values)

foreach(Subscriber s in subscribers.Values.ToList())

如果我是对的,问题就会消失

调用订阅者,值。ToList()将订阅者的值复制到Foreach开头的单独列表中。其他任何东西都无法访问这个列表(它甚至没有变量名!),所以在循环中没有任何东西可以修改它。


查看完整回答
反对 回复 2019-06-03
?
元芳怎么了

TA贡献1798条经验 获得超7个赞

当订阅服务器取消订阅时,您将在枚举期间更改订阅服务器集合的内容。

有几种方法可以解决这一问题,其中一种方法是更改for循环以使用显式.ToList():

public void NotifySubscribers(DataRecord sr)  {
    foreach(Subscriber s in subscribers.Values.ToList())
    {
                                              ^^^^^^^^^  
        ...


查看完整回答
反对 回复 2019-06-03
?
月关宝盒

TA贡献1772条经验 获得超5个赞

您还可以锁定订阅者字典,以防止当它被循环时被修改:

 lock (subscribers)
 {
         foreach (var subscriber in subscribers)
         {
               //do something
         }
 }


查看完整回答
反对 回复 2019-06-03
  • 4 回答
  • 0 关注
  • 881 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信