我有一个 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 无法修改,这是我将要接收的格式。
我希望这能准确解释我遇到的问题。我知道问题发生在哪里,但我只是完全不确定如何解决它。
最佳答案
首先,您可以考虑切换到 json.net 。如果这样做,您可以直接反序列化到 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 format由 JavaScriptSerializer
使用.
使用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/