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

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

我无法找到这个错误的底部,因为当附加调试器时,它似乎不会发生。下面是密码。

这是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);
        }
    }}


慕斯王
浏览 882回答 4
4回答

神不在的星期二

可能发生的是SignalData在循环期间间接地更改订阅者字典并导致消息。您可以通过更改foreach(Subscriber&nbsp;s&nbsp;in&nbsp;subscribers.Values)到foreach(Subscriber&nbsp;s&nbsp;in&nbsp;subscribers.Values.ToList())如果我是对的,问题就会消失调用订阅者,值。ToList()将订阅者的值复制到Foreach开头的单独列表中。其他任何东西都无法访问这个列表(它甚至没有变量名!),所以在循环中没有任何东西可以修改它。

元芳怎么了

当订阅服务器取消订阅时,您将在枚举期间更改订阅服务器集合的内容。有几种方法可以解决这一问题,其中一种方法是更改for循环以使用显式.ToList():public&nbsp;void&nbsp;NotifySubscribers(DataRecord&nbsp;sr)&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;foreach(Subscriber&nbsp;s&nbsp;in&nbsp;subscribers.Values.ToList()) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^^^^^^^^^&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...

月关宝盒

您还可以锁定订阅者字典,以防止当它被循环时被修改:&nbsp;lock&nbsp;(subscribers) &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(var&nbsp;subscriber&nbsp;in&nbsp;subscribers) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//do&nbsp;something &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;}
打开App,查看更多内容
随时随地看视频慕课网APP