2016-09-19 361 views
0

如何将JObject转换为3D数组?我有一个格式化为这样的JObject:将JObject转换为多维数组

{ 
    "0": [ 
    [ 
     1.0, 
     2.0, 
     3.0 
    ], 
    [ 
     4.0, 
     5.0, 
     6.0 
    ] 
    ], 
    "1": [ 
    [ 
     7.0, 
     8.0, 
     9.0 
    ], 
    [ 
     10.0, 
     11.0, 
     12.0 
    ] 
    ] 
} 

我已经试过了强制转换为double[,,]但它失败,错误陈述

Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'System.Double[,,]'. 

回答

1

对我来说,以下工作:

var deserailizationExp = JsonConvert.DeserializeObject<Dictionary<string, double[,]>>(@" 
      {""0"": [ 
      [ 
       1.0, 
       2.0, 
       3.0 
      ], 
      [ 
       4.0, 
       5.0, 
       6.0 
      ] 
      ], 
      ""1"": [ 
      [ 
       7.0, 
       8.0, 
       9.0 
      ], 
      [ 
       10.0, 
       11.0, 
       12.0 
      ] 
      ] 
     }"); 

然后,您可以直接使用字典或将其转换为数组。 编辑:正如在评论中指出的,你也可以考虑将其反序列化为SortedDictionary<int, double[,]>。我测试了它作为一种类型,它为我工作。

另外,如果你修改,你可以做以下的JSON:

var otherDes = JsonConvert.DeserializeObject<double[,,]>(@" 
      [[ 
      [ 
       1.0, 
       2.0, 
       3.0 
      ], 
      [ 
       4.0, 
       5.0, 
       6.0 
      ] 
      ], 
      [ 
      [ 
       7.0, 
       8.0, 
       9.0 
      ], 
      [ 
       10.0, 
       11.0, 
       12.0 
      ] 
      ] 
     ]"); 

正如你所看到的,我只是删除 “0” 和 “1” 和替换{}与[]。如果您有能力控制您以何种方式接收JSON,那么在我看来这可能是更好的解决方案,因为它符合您的请求类型,而无需对其执行任何进一步的操作。

+0

'Dictionary '也应该有效,因为属性名称显然是索引。注意'Dictionary'是无序的,因此在反序列化过程中条目的顺序可能会被打乱。 'SortedDictionary '会更好。 – dbc

+0

,但如果他从Web服务接收内容,则这不起作用 –

0

Json.NET期望多维数组的格式应该像JSON文件中的3d锯齿状数组,但是您的格式就像2d锯齿状数组字典。您可以使用custom JsonConverter以JSON这样的格式转换为3D阵列,像这样:

public class Array3DConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     if (!objectType.IsArray) 
      return false; 
     return objectType.GetArrayRank() == 3; 
    } 

    object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      // Handle case when it's actually a 3d array in the JSON. 
      var list = serializer.Deserialize<List<List<List<T>>>>(reader); 
      return list.Select((l, i) => new KeyValuePair<int, List<List<T>>>(i, l)).To3DArray(); 
     } 
     else if (reader.TokenType == JsonToken.StartObject) 
     { 
      // Handle case when it's a dictionary of key/value pairs. 
      var dictionary = serializer.Deserialize<SortedDictionary<int, List<List<T>>>>(reader); 
      return dictionary.To3DArray(); 
     } 
     else 
     { 
      throw new JsonSerializationException("Invalid reader.TokenType " + reader.TokenType); 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     try 
     { 
      var elementType = objectType.GetElementType(); 
      var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); 
      return method.MakeGenericMethod(new[] { elementType }).Invoke(this, new object[] { reader, objectType, existingValue, serializer }); 
     } 
     catch (TargetInvocationException ex) 
     { 
      // Wrap the TargetInvocationException in a JsonSerializerException 
      throw new JsonSerializationException("Failed to deserialize " + objectType, ex); 
     } 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static class EnumerableExtensions 
{ 
    public static T[,,] To3DArray<T>(this IEnumerable<KeyValuePair<int, List<List<T>>>> jaggedArray) 
    { 
     if (jaggedArray == null) 
      throw new ArgumentNullException("jaggedArray"); 
     var counts = new int[3]; 
     foreach (var pair in jaggedArray) 
     { 
      var i = pair.Key; 
      counts[0] = Math.Max(i + 1, counts[0]); 
      if (pair.Value == null) 
       continue; 
      var jCount = pair.Value.Count; 
      counts[1] = Math.Max(jCount, counts[1]); 
      for (int j = 0; j < jCount; j++) 
      { 
       if (pair.Value[j] == null) 
        continue; 
       var kCount = pair.Value[j].Count; 
       counts[2] = Math.Max(kCount, counts[2]); 
      } 
     } 
     var array = new T[counts[0], counts[1], counts[2]]; 
     foreach (var pair in jaggedArray) 
     { 
      var i = pair.Key; 
      if (pair.Value == null) 
       continue; 
      var jCount = pair.Value.Count; 
      for (int j = 0; j < jCount; j++) 
      { 
       if (pair.Value[j] == null) 
        continue; 
       var kCount = pair.Value[j].Count; 
       for (int k = 0; k < kCount; k++) 
        array[i, j, k] = pair.Value[j][k]; 
      } 
     } 
     return array; 
    } 
} 

然后使用它像:

var array = JsonConvert.DeserializeObject<double[, ,]>(jsonString, new JsonSerializerSettings { Converters = new[] { new Array3DConverter() } }); 

或者,如果你已经解析您的JSON字符串一个JObject,你可以使用JToken.ToObject<T>(JsonSerializer)使用转换器反序列化到你想要的类型:

var array = jObj.ToObject<double[, ,]>(JsonSerializer.CreateDefault(new JsonSerializerSettings { Converters = new[] { new Array3DConverter() } })); 

对于在使用中的灵活性,转换器测试查看传入的JSON是否被格式化为对象或数组并进行适当的响应。

注 - 仅轻微测试。