У меня имеется список элементов, которые присылаются c серверной стороны (присланные, к примеру, от PHP) используя [WWW(https://docs.unity3d.com/ScriptReference/WWW.html). Его контент (WWW.text) выглядит так:
[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]
Класс, который я использую выглядит так:
public class player {
public string playerId { get; set; }
public string playerLoc { get; set; }
public string playerNick { get; set; }
}
Пробовал десериализовать строку разными способами:
Boomlagoon.JSON
, но он почему-то извлекает только первый объект.Пытался использовать MiniJSON
: обрезал []
у присланной строки и затем применял библиотеку:
IDictionary<string,object> s = Json.Deserialize(serviceData) as IDictionary<string,object>;
foreach (KeyValuePair<string, object> kvp in s) {
Debug.Log(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
}
Но оно возвращает первое значение `KeyValuePair:
Key = playerId, Value = 1
Key = playerLoc, Value = Powai
А если оставить скобки, то вообще ничего не может распарсить json и поэтому логично в foreach
кидает ошибку:
NullReferenceException: Object reference not set to an instance of an object
Как мне корректно сериализовать и десериализовать данные из json? Что использовать и как?
Перевод вопроса http://stackoverflow.com/q/36239705/6104996
Начиная с версии 5.3.3 Unity добавила JsonUtility в своё API. Можете забыть о различных сторонних библиотеках, разве что вы не делаете что-то очень сложное.
JsonUtility быстрее, чем эти сторонние библиотеки, но и, меж тем, поддерживаются только просты типы. Оно не поддерживает коллекции, такие как словарь (Dictionary). Исключением является список (List). Оно поддерживает списки (List) и массив списков (List array).
Если вам нужно сериализовать словарь (Dictionary) или сделать что-то, чем простая сериализация и десеризация простых типов — используйте сторонние библиотеки. В ином же случае обновитесь до версии >= 5.3.3 и попробуйте решения, которые приведены ниже.
Пример класса для сериализации:
[Serializable]
public class Player {
public string playerId;
public string playerLoc;
public string playerNick;
}
1. ОДИН ОБЪЕКТ (НЕ JSON МАССИВ)
Исходные данные:
Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";
Сериализация 1:
Сериализация в json с помощью метода public static string ToJson(object obj);.
string playerToJson = JsonUtility.ToJson(playerInstance);
Debug.Log(playerToJson);
Output:
{"playerId":"8484239823","playerLoc":"Powai","playerNick":"Random Nick"}
Сериализация 2:
Сериализация в json с помощью перегруженного метода public static string ToJson(object obj, bool prettyPrint);.
Добавив флаг true
вторым аргументом в функцию JsonUtility.ToJson
отформатирует данные. Сравните вывод ниже с выводом, что был выше.
string playerToJson = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJson);
Output:
{
"playerId": "8484239823",
"playerLoc": "Powai",
"playerNick": "Random Nick"
}
Десериализация 1:
Десериализация json c помощью метода public static T FromJson(string json);.
string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = JsonUtility.FromJson<Player>(jsonString);
Debug.Log(player.playerLoc);
Десериализация 2:
Десериализация json c помощью перегруженного метода public static object FromJson(string json, Type type);.
string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = (Player)JsonUtility.FromJson(jsonString, typeof(Player));
Debug.Log(player.playerLoc);
Десериализация 3:
Десериализация json c помощью метода public static void FromJsonOverwrite(string json, object objectToOverwrite);.
Когда используется метод JsonUtility.FromJsonOverwrite
, то новый экземпляр объекта не будет создан, а будет переиспользован объект, который вы передадите в качестве параметра в функцию, перезаписав его значения.
Player playerInstance;
void Start() {
// создаем экземпляр объекта
playerInstance = new Player();
deserialize();
}
void deserialize() {
string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
// Перезаписываем значения уже существующего экземпляра класса "playerInstance". Меньше затрат памяти.
JsonUtility.FromJsonOverwrite(jsonString, playerInstance);
Debug.Log(playerInstance.playerLoc);
}
2. МНОЖЕСТВО ДАННЫХ (массив json): ваш json содержит несколько объектов с данными.
JsonUtility пока в нативном виде не поддерживает массивы, но можно воспользоваться небольшим классом-хэлпером, чтобы получить массив, который будет работать с JsonUtility.
Создаем класс JsonHelper
. Можете скопировать код хэлпера, представленного ниже:
public static class JsonHelper {
public static T[] FromJson<T>(string json) {
Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
return wrapper.Items;
}
public static string ToJson<T>(T[] array) {
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper);
}
public static string ToJson<T>(T[] array, bool prettyPrint) {
Wrapper<T> wrapper = new Wrapper<T>();
wrapper.Items = array;
return JsonUtility.ToJson(wrapper, prettyPrint);
}
[Serializable]
private class Wrapper<T> {
public T[] Items;
}
}
Сериализация json массива:
Player[] playerInstance = new Player[2];
playerInstance[0] = new Player();
playerInstance[0].playerId = "8484239823";
playerInstance[0].playerLoc = "Powai";
playerInstance[0].playerNick = "Random Nick";
playerInstance[1] = new Player();
playerInstance[1].playerId = "512343283";
playerInstance[1].playerLoc = "User2";
playerInstance[1].playerNick = "Rand Nick 2";
// Конвертируем в json
string playerToJson = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJson);
Output:
{
"Items": [
{
"playerId": "8484239823",
"playerLoc": "Powai",
"playerNick": "Random Nick"
},
{
"playerId": "512343283",
"playerLoc": "User2",
"playerNick": "Rand Nick 2"
}
]
}
Десериализация json массива:
string jsonString = "{\r\n \"Items\": [\r\n {\r\n \"playerId\": \"8484239823\",\r\n \"playerLoc\": \"Powai\",\r\n \"playerNick\": \"Random Nick\"\r\n },\r\n {\r\n \"playerId\": \"512343283\",\r\n \"playerLoc\": \"User2\",\r\n \"playerNick\": \"Rand Nick 2\"\r\n }\r\n ]\r\n}";
Player[] player = JsonHelper.FromJson<Player>(jsonString);
Debug.Log(player[0].playerLoc);
Debug.Log(player[1].playerLoc);
Output:
Powai
User2
Примечание: если данный json массив приходит с сервера и вы не создаете его самолично вручную, то тогда надо добавить {"Items":
в начало полученной строки и }
— в конец данной строки.
Вот простая функция, чтобы сделать это:
string fixJson(string value) {
value = "{\"Items\":" + value + "}";
return value;
}
Затем использовать её:
string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);
3. ИСПРАВЛЕНИЕ ПРОБЛЕМ JsonUtility:
Возникают проблемы при сериализации при использовании JsonUtility.ToJson? Получаете пустую строку или "{}
"?
JsonHelper.ToJson
, вместо JsonUtility.ToJson
.[Serializable]
сверху над объявлением класса, который вы хотите сериализовать. public string playerId { get; set; }
удалите { get; set; }
. Unity не сможет сериализовать их.Проблемы при десериализации при использовании JsonUtility.FromJson
?
Null
, то убедитесь, что json не является json массивом. Если это так, то используйте класс-хэлпер выше и его метод JsonHelper.FromJson
вместо JsonUtility.FromJson
.NullReferenceException
в процессе десериализации, то добавьте атрибут [Serializable]
сверху над объявлением класса.Отвечая, на ваш вопрос:
Ваши первоначальные данные:
[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]
Добавьте {"Items":
в начало этой строки и добавьте }
в конец этой строки.
Код выглядит так:
serviceData = "{\"Items\":" + serviceData + "}";
Теперь у вас есть строка:
{"Items":[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]}
Чтобы сериализовать теперь это множество данных из php как массивы, вы можете сделать так:
public player[] playerInstance;
playerInstance = JsonHelper.FromJson<player>(serviceData);
playerInstance[0]
— данные из первого объектаplayerInstance[1]
— данные из второго объектаplayerInstance[2]
— данные из третьего объектаПримечание: Удалите { get; set; }
из класса player
. Если у вас имеются { get; set; }
, то работать не будет. JsonUtility НЕ работает с членами класса, которые объявлены как свойства.
Если они нужны, тогда придется использовать либо другие библиотеки, либо XmlSerializer/BinaryFormatter
Перевод ответа http://stackoverflow.com/a/36244111/6104996
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Подскажите, пожалуйста, как можно получить информацию о месте клика при работе с WebBrowser
Есть БД MS SQL, в ней есть записи содержащие информацию о человеке (ФИО, возраст, город)Хочу сделать чтобы при добавлении новой записи была выполнена...
Здравствуйте, подскажите пожалуйста как можно реализовать загрузку файла(например изtxt вида логин/пароль) на языке с# при помощи библиотеки...
Нужно авторизоваться на сайте по протоколу https - при помощи WebRequest и WebResponse (сама программа на ASPNET MVC)