2016-09-19 2 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

'Словарь ' также должен работать, поскольку имена свойств явно являются индексами. Следите за тем, что «Словарь» неупорядочен, поэтому порядок записей может быть скремблирован во время десериализации. 'SortedDictionary ' будет лучше. – dbc

+0

, но это не сработает, если он получает контент из веб-службы –

0

Json.NET ожидает, что многомерный массив будет отформатирован как 3D-зубчатый массив в JSON-файле, однако ваш формат отформатирован как словарь из 2-х зубчатых массивов. Вы можете использовать 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() } })); 

гибкости в использовании, конвертер тесты в сек ee ли входящий JSON отформатирован как объект или массив и отвечает соответствующим образом.

Примечание - только слегка протестировано.