反序列化的jsonObject得到更新,foreach然后失败

时间:2016-11-14 11:16:44

标签: c# foreach json.net

我有一个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产生和错误似乎是合乎逻辑的,但为什么还会发生呢?

任何暗示都赞赏......

2 个答案:

答案 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