遍历从 JSON 文件生成的动态对象的问题

Issues Iterating through a dynamic object generated from a JSON file

我有一个 json 文件(为了这个问题)我简化了它:

{
  "servername": {
    "goodvolumes": [
      {
        "Name": "vol1",
        "State": "online",
        "Size": "12.0 TB"
      },
      {
        "Name": "vol2",
        "State": "online",
        "Size": "10.0 TB"
      }
    ],
    "BadVolumes": {
      "Name": "badVol",
      "State": "offline",
      "TotalSize": "120GB"
    }
  }
}

当它被读入我的 C# 时,我有一个类型为 System.Collections.Generic.Dictionary<string,object> 的数据对象。

然后我遍历该对象并创建一个模型对象,我将把它传递给我的视图。

这对我来说是个难题。这是我如何遍历 json.

的示例
//top level of my JSON - the serverName
foreach(serverName in jsonData) 
{
    //record the serverName

    //second level of my JSON - the notification name
    foreach(notification in serverName.Value)
    {
        //record the notification name

        //3rd Level of my JSON - iterating the entries
        foreach(entry in notification.Value)
        {
            //Iterating all the values in an entry
            foreach(entryValue in entry)
            {
               //record values in each entry
            }

        }
    }
}

我遇到的问题是在只有 1 个条目的情况下迭代第三级时。

根据 JSON 的性质,如果通知类型有多个条目,那么在我的 notifications.Value 中将有另一个集合列表。在这种情况下,我的代码就像一个魅力。

但是,如果通知只有 1 个条目,notification.value 实际上包含单个条目中所有值的 KeyValuePair 列表。所以第 3 级迭代不起作用。它实际上是在尝试迭代该点的值。

很遗憾,我正在使用的 json 无法修改,这是我将要接收的格式。

我希望这能准确解释我遇到的问题。我知道问题出在哪里,只是完全不确定如何解决它。

首先,您可以考虑切换到 JavaScriptSerializer 使用的 . If you do, you could deserialize directly to a Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> using SingleOrArrayConverter<Dictionary<string, string>> from How to handle both a single item and an array for the same property using JSON.net. This also avoids the proprietary date format

使用 JavaScriptSerializer,您需要了解它如何反序列化任意 JSON 数据的一些细节。具体来说,它将 JSON 对象反序列化为 IDictionary<string, object> 和 JSON 数组作为某种 非字典,非 string IEnumerable。以下扩展方法实现了这些检查:

public static class JavaScriptSerializerObjectExtensions
{
    public static bool IsJsonArray(this object obj)
    {
        if (obj is string || obj.IsJsonObject())
            return false;
        return obj is IEnumerable;
    }

    public static IEnumerable<object> AsJsonArray(this object obj)
    {
        if (obj is string || obj.IsJsonObject())
            return null;
        return (obj as IEnumerable).Cast<object>();
    }

    public static bool IsJsonObject(this object obj)
    {
        return obj is IDictionary<string, object>;
    }

    public static IDictionary<string, object> AsJsonObject(this object obj)
    {
        return obj as IDictionary<string, object>;
    }

    /// <summary>
    /// If the incoming object corresponds to a JSON array, return it.  Otherwise wrap it in an array.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static IEnumerable<object> ToJsonArray(this object obj)
    {
        if (obj.IsJsonArray())
            return obj.AsJsonArray();
        return new[] { obj };
    }

    public static string JsonPrimitiveToString(this object obj, bool isoDateFormat = true)
    {
        if (obj == null)
            return null; // Or return "null" if you prefer.
        else if (obj is string)
            return (string)obj;
        else if (obj.IsJsonArray() || obj.IsJsonObject())
            return new JavaScriptSerializer().Serialize(obj);
        else if (isoDateFormat && obj is DateTime)
            // Return in ISO 8601 format not idiosyncratic JavaScriptSerializer format
            // 
            // https://msdn.microsoft.com/en-us/library/az4se3k1.aspx#Roundtrip
            return ((DateTime)obj).ToString("o");
        else
        {
            var s = new JavaScriptSerializer().Serialize(obj);
            if (s.Length > 1 && s.StartsWith("\"", StringComparison.Ordinal) && s.EndsWith("\"", StringComparison.Ordinal))
                s = s.Substring(1, s.Length - 2);
            return s;
        }
    }
}

然后可以反序列化如下:

var jsonData = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(jsonString);

Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>> finalData;

// I could have just done var finalData = ... here.  I declared finalData explicitly to makes its type explicit.
finalData =
    jsonData.ToDictionary(
    p1 => p1.Key,
    p1 => p1.Value
        .AsJsonObject()
        .ToDictionary(
            p2 => p2.Key,
            p2 => (p2.Value.ToJsonArray().Select(a => a.AsJsonObject())).Select(o => o.ToDictionary(p3 => p3.Key, p3 => p3.Value.JsonPrimitiveToString())).ToList()
        ));

现在您已经有了完全类型化的字典层次结构,您应该可以继续创建最终模型了。