一尘不染

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

c#

我无法弄清此错误的原因,因为在连接调试器时,似乎没有发生此错误。下面是代码。

这是Windows服务中的WCF服务器。每当有数据事件时,服务就会调用NotifySubscribers方法(以随机间隔,但不是很频繁-每天大约800次)。

Windows
Forms客户端进行预订时,订户ID被添加到订户字典中,而当客户端取消订阅时,将从该字典中删除它。该错误发生在客户退订时(或之后)。看来,下次调用NotifySubscribers()方法时,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);
        }
    }
}

阅读 369

收藏
2020-05-19

共1个答案

一尘不染

可能发生的情况是,SignalData在循环期间间接更改了后台的订户字典并导致该消息。您可以通过更改

foreach(Subscriber s in subscribers.Values)

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

如果我说对了,问题就会消失

呼叫subscribers.Values.ToList()将的值复制subscribers.Values到的开头foreach。没有其他人可以访问此列表(它甚至没有变量名!),因此在循环内没有人可以对其进行修改。

2020-05-19