Как проанализировать массив объектов json, содержащий смешанные типы примитивов, используя DataContractJsonSerializer?

Как я могу разобрать объект JSON ниже, используя DataContractJsonSerializer в C#?

Мне нужно будет определить класс для хранения приведенных ниже данных JSON, который включает в себя массив массивов примитивов смешанных типов (строки и целые числа):

Body:
    {
      "status": "failure",
      "staticdata": [
        [
          "2013-06-01",
          123
        ],
        [
          "2013-06-02",
          234
        ],
        [
          "2013-06-03",
          345
        ],    
        ...
      ]
    }

Я попробовал ответ ниже и попытался прочитать DataContractJsonSerializer,

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (object[] sd in jsonResponse.staticdata)
{
    foreach (object o in sd)
    {
        //Value val = v as Value;
        Value val = (Value)Convert.ChangeType(o, typeof(Value));
            log.Info("date: " + val.date);
            log.Info("crashCount: " + val.longValue);
   }
} 

но в converttype от объекта до значения происходит сбой, я что-то здесь упускаю.

Значение ниже класса:

[DataContract]
public class Value
{
    [DataMember(Name = "date")]
    public string date { get; set; }

    [DataMember(Name = "longValue")]
    public long longValue{ get; set; }
}

модифицированный код считывает значения (значения IgnoreDataMember), а затем может читать, как показано ниже: это правильный подход?

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (Value in jsonResponse.Values)
{
            log.Info("date: " + val.date);
            log.Info("longValue: " + val.longValue);
} 

1 ответ

Если вы просто хотите десериализовать свой JSON, вы можете использовать инструмент генерации кода, например http://json2csharp.com/ или Вставить JSON As Classes, и получить следующую модель данных, которая прекрасно работает с DataContractJsonSerializer:

public class RootObject
{
    public string status { get; set; }
    public List<List<object>> staticdata { get; set; }
}

object работает потому что DataContractJsonSerializer автоматически распознает и сериализует известные примитивные типы, такие как string а также int,

Но то, что вы можете захотеть, это десериализовать "staticdata" массив для списка классов, таких как этот:

public class Value
{
    public string Date { get; set; }
    public int IntValue { get; set; }
}

Если это так, вы можете использовать суррогатное имущество в RootObject введите преобразование:

[DataContract]
public class RootObject
{
    [DataMember]
    public string status { get; set; }

    [DataMember]
    object[][] staticdata
    {
        get
        {
            if (Values == null)
                return null;
            return Values.Select(v => new object[] { v.Date, v.IntValue }).ToArray();
        }
        set
        {
            if (value == null)
                return;
            Values = value.Select(a => new Value 
                { 
                    Date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
                    IntValue = a.Length < 2 ? 0 : (int)Convert.ChangeType(a[1], typeof(int), CultureInfo.InvariantCulture) 
                }
                ).ToList();
        }
    }

    [IgnoreDataMember]
    public List<Value> Values { get; set; }
}

Обновить

В обновленном вопросе, который вы задали, но при конвертировании из объекта в значение происходит сбой, я что-то здесь упускаю?

Ваша проблема в том, что вы пытаетесь использовать Convert.ChangeType()преобразоватьobjectкValue, но этот метод предназначен только для примитивных типов данных, которые могут быть преобразованы из и в строки. Из документов:

ChangeType - это метод преобразования общего назначения, который преобразует объект, указанный в значении, в преобразование типа. Параметр value может быть объектом любого типа, а translationType также может быть объектом Type, представляющим любой базовый или пользовательский тип.Чтобы преобразование прошло успешно, значение должно содержатьIConvertibleинтерфейс, потому что метод просто переносит вызов к соответствующемуIConvertible метод.

Как твой Value Тип не реализует этот интерфейс, преобразование не выполняется.

Вместо этого вы должны использовать Convert.ChangeType на отдельные записи во вложенных массивах. Учитывая ваш RootObject похоже:

public class RootObject
{
    public string status { get; set; }
    public object [][] staticdata { get; set; }
}

Ты должен сделать:

using System.Linq;

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
var jsonResponse = (RootObject)jsonSerializer.ReadObject(response);

var query = jsonResponse.staticdata
    // For each object [] array in the outer array
    .Select(a => new Value
        {
             // Convert the inner array to a Value, using the first element for the date and the second element for the longValueand the second element for the longValue
            date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
            longValue = a.Length < 2 ? 0 : (long)Convert.ChangeType(a[1], typeof(long), CultureInfo.InvariantCulture)
        });

foreach (var val in query)
{
    log.Info("date: " + val.date);
    log.Info("crashCount: " + val.longValue);
}
Другие вопросы по тегам