c# - 迭代从 JSON 文件生成的动态对象的问题

标签 c# json loops dictionary javascriptserializer

我有一个 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> 类型的数据对象.

然后,我将迭代该对象并创建一个模型对象,并将其传递到我的 View 。

这给我带来了困难。下面是我如何迭代 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 的列表对于单个条目内的所有值。所以第三级迭代不起作用。它实际上是在尝试迭代此时的值。

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

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

最佳答案

首先,您可以考虑切换到 。如果这样做,您可以直接反序列化到 Dictionary<string, Dictionary<string, List<Dictionary<string, string>>>>使用SingleOrArrayConverter<Dictionary<string, string>>来自How to handle both a single item and an array for the same property using JSON.net 。这也避免了 proprietary date formatJavaScriptSerializer 使用.

使用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://stackoverflow.com/questions/17301229/deserialize-iso-8601-date-time-string-to-c-sharp-datetime
            // 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()
        ));

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

关于c# - 迭代从 JSON 文件生成的动态对象的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36988114/

相关文章:

c# - Windows UI Automation API 在服务器上运行时找不到子元素

c# - 在 WebApi 中序列化多个枚举值

javascript - 显示带有警报的 JSON 数组的数据

python - 循环遍历列表然后在 python 中使用双循环的更有效方法

bash - 在 bash 中创建直方图

c# 3.0 转换接口(interface)泛型类型

json - 在 Azure 函数中引用 Newtonsoft.Json

javascript - 如何在 react 中进行双json外部调用

javascript - 使用 javascript 循环访问 div 中的链接

c# - 在google身份验证中将用户信息存入数据库