我有一个json文件,我使用Newtonssoft Json.Net反序列化:
/* Get current config */
dynamic json = JsonConvert.DeserializeObject<Speaker>(
File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + "cfg\\speaker.json"));
dynamic jsonDevice = json.DeviceList;
/* Go through the List */
foreach (Tapi tapi in lvTapiSonos.Items)
{
foreach (var line in jsonDevice)
{
foreach (var l in line)
{
/* If not in List already, add it */
if (l.Key != tapi.Name)
{
/* Add to Config */
json.DeviceList.Add(new Dictionary<string, List<Device>>
{
{
tapi.Name,
new List<Device>
{
new Device
{
Volume = "5",
Ip = currentEditIp,
Name = currentEditName
}
}
}
});
}
}
}
}
string output = JsonConvert.SerializeObject(json, Formatting.Indented);
File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "cfg\\speaker.json", output);
不幸的是,这只适用于第一个foreach
因为我得到了一个例外“列表已经改变。枚举不能继续”(与我在德语中的类似)在行foreach (var line in jsonDevice)
中。
我理解这意味着,jsonDevice
已更新(现在又显示调试中的一个项目),但由于我在foreach之外分配了jsonDevice
,它是如何更新的?当我更新foreach中的json对象时,foreach var line in json.DeviceList
产生和错误似乎是合乎逻辑的,但为什么还会发生呢?
任何暗示都赞赏......
答案 0 :(得分:3)
foreach语句用于遍历集合以获取 您想要的信息,但不能用于添加或删除 来自源集合的项目,以避免不可预测的副作用。 如果需要在源集合中添加或删除项目,请使用 for循环。 http://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx
如上所述,您可以为您的用例使用for循环。但如果你调用ToList()或ToArray,你可以获得可用于迭代的项目的副本
dynamic jsonDevice = json.DeviceList.ToList();
答案 1 :(得分:1)
以下是此处的非法代码:
json.DeviceList.Add(new Dictionary<string, List<Device>>
为什么?
在foreach
中,您获得了集合的枚举器,即read-only forward moving
,您无法更改foreach
循环内的原始来源。您正在访问jsonDevice
,这是json.DeviceList
集合的参考副本,已修改
怎么做:
转换为for
循环并按索引访问,然后您可以在通过索引访问时更改任何集合,而不是使用附加的枚举器更改原始集合
或者
创建集合的深层副本,创建新对象并复制所有值成员和所有引用类型的深层副本。您可以覆盖基础对象类的Memberwiseclone