我无法弄清此错误的原因,因为在连接调试器时,似乎没有发生此错误。下面是代码。
这是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); } } }
可能发生的情况是,SignalData在循环期间间接更改了后台的订户字典并导致该消息。您可以通过更改
foreach(Subscriber s in subscribers.Values)
至
foreach(Subscriber s in subscribers.Values.ToList())
如果我说对了,问题就会消失
呼叫subscribers.Values.ToList()将的值复制subscribers.Values到的开头foreach。没有其他人可以访问此列表(它甚至没有变量名!),因此在循环内没有人可以对其进行修改。
subscribers.Values.ToList()
subscribers.Values
foreach