.jpg)
我无法深入了解此错误,因为当附加调试器时,它似乎没有发生。集合已修改;枚举操作可能无法执行
下面是代码。
这是 Windows 服务中的 WCF 服务器。每当存在数据事件(以随机间隔,但不经常 – 每天大约 800 次)时,服务都会调用该方法。NotifySubscribers()
当 Windows 窗体客户端订阅时,订阅者 ID 将添加到订阅者字典中,当客户端取消订阅时,订阅者 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);
}
}
}

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

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

网友回答:
在我看来,更有效的方法是有另一个列表,你声明你把任何“要删除”的东西放进去。然后在完成主循环后(没有 .ToList()),您可以在“要删除”列表上执行另一个循环,在发生时删除每个条目。所以在你的课堂上,你添加:
private List<Guid> toBeRemoved = new List<Guid>();
然后将其更改为:
public void NotifySubscribers(DataRecord sr)
{
toBeRemoved.Clear();
...your unchanged code skipped...
foreach ( Guid clientId in toBeRemoved )
{
try
{
subscribers.Remove(clientId);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("Unsubscribe Error " +
e.Message);
}
}
}
...your unchanged code skipped...
public void UnsubscribeEvent(Guid clientId)
{
toBeRemoved.Add( clientId );
}
这不仅可以解决您的问题,还可以防止您继续从字典中创建列表,如果那里有很多订阅者,这将很昂贵。假设在任何给定迭代中要删除的订阅者列表低于列表中的总数,这应该更快。但是,当然,如果您的特定使用情况有任何疑问,请随意对其进行分析,以确保情况确实如此。
模板简介:该模板名称为【集合已修改;枚举操作可能无法执行,如何处理。】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。