Десериализация массива JSON смешанных типов

У меня возникли проблемы с десериализацией массива смешанных типов JSON с использованием класса DataContractJsonSerializer. Я потратил кучу времени на поиски решения безрезультатно, поэтому я решил пойти дальше и спросить здесь.

По сути, я получаю строку JSON, подобную приведенной ниже. Я хотел бы получить массив для десериализации в список, где позиция 0 имеет Int32, позиция 1 имеет String, а позиция 2 имеет экземпляр моего пользовательского класса.

[
   2,
   "Mr. Smith",
   {
      "num":169,
      "name":"main street",
      "state":66
   }
]

Если я просто создам сериализацию так:

DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(List<object>))

На самом деле я получаю Int32 в позиции 0 и String в позиции 1. Однако в позиции 2 я просто получаю нулевой объект.

Кто-нибудь знает, возможно ли то, что я пытаюсь сделать? У меня нет контроля над структурой JSON, которую я потребляю. Я хотел бы сделать это без использования сторонних сборок, если это возможно.


person Mike    schedule 11.10.2010    source источник


Ответы (2)


Вы должны создать класс, который воспроизводит структуру json следующим образом:

[DataContract]
public class MyClass {
    [DataMember]
    public int IntMember { get; set; }
    [DataMember]
    public string StringMember { get; set; }
    [DataMember]
    public MyType[] AllTypes { get; set;}
}

[DataContract]
public class MyType {
    [DataMember]
    public int num { get; set; }
    [DataMember]
    public string name { get; set; }
    [DataMember]
    public int state { get; set;}
}

Украсьте класс и его свойства атрибутами DataContract и DataMember. Затем в коде десериализации используйте созданный вами класс, как в следующем примере.

var serializer = new DataContractJsonSerializer(typeof(MyClass));
System.IO.StringReader reader = new System.IO.StringReader(jsonData);
System.IO.MemoryStream ms = new System.IO.MemoryStream(Encoding.Default.GetBytes(jsonData));
return serializer.ReadObject(ms) as MyClass;
person Lorenzo    schedule 11.10.2010
comment
Тоже так думал изначально. Проблема в том, что такой массив не будет десериализоваться в один класс. Сериализатор заставляет это десериализоваться как массив. Когда я попробовал это, я получил сообщение об ошибке «Ожидание состояния «Элемент».. Обнаружен текст с именем '', пространство имен ''. - person Mike; 11.10.2010
comment
Пожалуйста, взгляните на мое последнее редактирование. Я забыл, что это массив элементов... - person Lorenzo; 11.10.2010
comment
Лоренцо, спасибо за пример кода. Кажется, это тоже не работает. Это создает экземпляр MyClass с членом int = 0 и null для двух других членов. Чего-то еще не хватает... - person Mike; 11.10.2010
comment
@Mike: Пожалуйста, посмотрите здесь: http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx. Помимо аргумента статьи, в классе GridModelBinder есть фрагмент кода, который делает что-то в точности как в вашем образце. И это работает, поверьте мне. :) - person Lorenzo; 11.10.2010

Майк,

Проблема в том, что во время десериализации десериализатор JSON не знает, в какой тип десериализовать элемент в позиции 2.

Вам нужно предоставить подсказку "__type". Вы можете получить подсказку __type для конкретного типа, фактически сериализовав его в JSON в полиморфной ситуации и увидев, какая подсказка типа выдается.

Дополнительные сведения см. на странице http://msdn.microsoft.com/en-us/library/bb412170.aspx. Обратите особое внимание на разделы «Коллекции, назначенные объекту» и «Сохранение информации о типе».

person krisragh MSFT    schedule 02.02.2011