在 Unity 中序列化和反序列化 Json 和 Json 数组

Serialize and Deserialize Json and Json Array in Unity

提问人:dil33pm 提问时间:3/27/2016 最后编辑:Snakdil33pm 更新时间:7/16/2023 访问量:276231

问:

我有一个使用 PHP 文件发送到 unity 的项目列表。WWW

如下所示:WWW.text

[
    {
        "playerId": "1",
        "playerLoc": "Powai"
    },
    {
        "playerId": "2",
        "playerLoc": "Andheri"
    },
    {
        "playerId": "3",
        "playerLoc": "Churchgate"
    }
]

我从 .当我尝试使用 解析它时,只检索第一个对象。我发现我必须进入列表并导入了 MiniJSON。[]stringBoomlagoon.JSONdeserialize()

但是我很困惑如何列出这个列表。我想遍历每个JSON对象并检索数据。如何使用 C# 在 Unity 中执行此操作?deserialize()

我使用的类是

public class player
{
    public string playerId { get; set; }
    public string playerLoc { get; set; }
    public string playerNick { get; set; }
}

修剪后,我可以使用 MiniJSON 解析 json。但它只返回第一个.[]KeyValuePair

IDictionary<string, object> players = Json.Deserialize(serviceData) as IDictionary<string, object>;

foreach (KeyValuePair<string, object> kvp in players)
{
    Debug.Log(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
}

谢谢!

C# JSON unity-游戏引擎

评论

0赞 Jon Skeet 3/27/2016
你为什么要去掉外面的?这就是使它成为列表的原因。只需停止删除它,并将其反序列化为数组或列表,我希望它没问题。请发布您尝试过的代码。[]
0赞 Maximilian Gerhardt 3/27/2016
向我们展示用于反序列化的类。格式很奇怪,为什么第二个 playerId 没有包裹在大括号内?它应该反序列化为某个内容的列表,例如 ,因为这是一个数组List<PlayerLocation>
0赞 dil33pm 3/27/2016
@MaximilianGerhardt 对不起,大括号是错别字。在问题中修复了它,并添加了代码。谢谢。
1赞 Maximilian Gerhardt 3/27/2016
我认为您对这个库如何处理反序列化的理解有问题。这不是通常的反序列化(正如您可能在 中看到的那样),但是 ALWAYS 返回 a 给您并且您对 .看看 stackoverflow.com/a/22745634/5296568.最好使用更好的 JSON 反序列化程序来执行您习惯的反序列化。Newtonsoft.JsonJson.Deserialize()IDictionary<string,object>List<object>
0赞 dil33pm 3/27/2016
@MaximilianGerhardt我尝试过.我能够得到价值,但只有第一个.IDictionary<string,object>KeyValuePair<>

答:

-1赞 Thomas Hilbert 3/27/2016 #1

不要修剪,你应该没事。 标识一个 JSON 数组,该数组正是您能够迭代其元素所需的。[][]

0赞 dil33pm 3/27/2016 #2

就像@Maximiliangerhardt说的,MiniJson没有正确反序列化的能力。我使用了 JsonFx 并且像魅力一样工作。与[]

player[] p = JsonReader.Deserialize<player[]>(serviceData);
Debug.Log(p[0].playerId +" "+ p[0].playerLoc+"--"+ p[1].playerId + " " + p[1].playerLoc+"--"+ p[2].playerId + " " + p[2].playerLoc);
356赞 Programmer 3/27/2016 #3

Unity 在 5.3.3 更新后将 JsonUtility 添加到其 API 中。忘记所有第三方库,除非您正在做一些更复杂的事情。JsonUtility 比其他 Json 库更快。更新到 Unity 5.3.3 或更高版本,然后尝试以下解决方案。

JsonUtility是一个轻量级的 API。仅支持简单类型。它不支持 Dictionary 等集合。一个例外是 。它支持和阵列!ListListList

如果需要序列化或执行除简单地序列化和反序列化简单数据类型以外的其他操作,请使用第三方 API。否则,请继续阅读。Dictionary

要序列化的示例类:

[Serializable]
public class Player
{
    public string playerId;
    public string playerLoc;
    public string playerNick;
}

1. 一个数据对象(非数组 JSON)

序列化 A 部分

使用公共静态字符串 ToJson(object obj); 方法序列化为 Json。

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance);
Debug.Log(playerToJson);

输出

{"playerId":"8484239823","playerLoc":"Powai","playerNick":"Random Nick"}

序列化 B 部分

使用公共静态字符串 ToJson(object obj, bool prettyPrint); 方法重载序列化为 Json。只需传递给函数即可格式化数据。将下面的输出与上面的输出进行比较。trueJsonUtility.ToJson

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJson);

输出

{
    "playerId": "8484239823",
    "playerLoc": "Powai",
    "playerNick": "Random Nick"
}

反序列化 A 部分

使用公共静态 T FromJson(string json); 方法重载反序列化 json。

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = JsonUtility.FromJson<Player>(jsonString);
Debug.Log(player.playerLoc);

反序列化 B 部分

使用公共静态对象 FromJson(string json, Type type); 方法重载反序列化 json。

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = (Player)JsonUtility.FromJson(jsonString, typeof(Player));
Debug.Log(player.playerLoc);

反序列化 C 部分

使用公共静态 void FromJsonOverwrite(string json, object objectToOverwrite); 方法反序列化 json。使用时,不会创建要反序列化到的该 Object 的新实例。它只会重用您传入的实例并覆盖其值。JsonUtility.FromJsonOverwrite

这是有效的,如果可能,应该使用。

Player playerInstance;
void Start()
{
    //Must create instance once
    playerInstance = new Player();
    deserialize();
}

void deserialize()
{
    string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";

    //Overwrite the values in the existing class instance "playerInstance". Less memory Allocation
    JsonUtility.FromJsonOverwrite(jsonString, playerInstance);
    Debug.Log(playerInstance.playerLoc);
}

2. 多个数据(数组JSON)

您的 Json 包含多个数据对象。例如,出现不止一次。Unity 不支持数组,因为它仍然是新的,但您可以使用此人的帮助程序类来获取数组playerIdJsonUtilityJsonUtility

创建一个名为 的类。直接从下面复制 JsonHelper。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";

//Convert to JSON
string playerToJson = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJson);

输出

{
    "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);

输出

波瓦伊

用户 2


如果这是来自服务器的 Json 数组,并且您不是手动创建的

您可能需要在收到的字符串前面添加,然后在其末尾添加。{"Items":}

我为此做了一个简单的函数:

string fixJson(string value)
{
    value = "{\"Items\":" + value + "}";
    return value;
}

然后你可以使用它:

string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);

3.反序列化没有类的json字符串,&>使用数值属性反序列化Json

这是一个以数字或数字属性开头的 Json。

例如:

{ 
"USD" : {"15m" : 1740.01, "last" : 1740.01, "buy" : 1740.01, "sell" : 1744.74, "symbol" : "$"}, 

"ISK" : {"15m" : 179479.11, "last" : 179479.11, "buy" : 179479.11, "sell" : 179967, "symbol" : "kr"},

"NZD" : {"15m" : 2522.84, "last" : 2522.84, "buy" : 2522.84, "sell" : 2529.69, "symbol" : "$"}
}

Unity 不支持此功能,因为“15m”属性以数字开头。类变量不能以整数开头。JsonUtility

从 Unity 的 wiki 下载 SimpleJSON.cs

要获得 USD 的“15m”属性:

var N = JSON.Parse(yourJsonString);
string price = N["USD"]["15m"].Value;
Debug.Log(price);

要获取 ISK 的“15m”属性,请执行以下操作:

var N = JSON.Parse(yourJsonString);
string price = N["ISK"]["15m"].Value;
Debug.Log(price);

要获得新西兰元的“15m”属性:

var N = JSON.Parse(yourJsonString);
string price = N["NZD"]["15m"].Value;
Debug.Log(price);

其余不以数字开头的 Json 属性可以由 Unity 的 JsonUtility 处理。


4.JsonUtility故障排除:

使用 JsonUtility.ToJson 序列化时出现问题?

获取空字符串或带有 “” 的 ?{}JsonUtility.ToJson

:确保该类不是数组。如果是,请使用上面的帮助程序类,而不是 .JsonHelper.ToJsonJsonUtility.ToJson

B.B. 添加到要序列化的类的顶部。[Serializable]

C.C. 从类中删除属性。例如,在变量中,删除 .Unity 无法对此进行序列化。public string playerId { get; set; }{ get; set; }

使用 JsonUtility.FromJson 反序列化时出现问题?

:如果得到 ,请确保 Json 不是 Json 数组。如果是,请使用上面的帮助程序类,而不是 .NullJsonHelper.FromJsonJsonUtility.FromJson

B. 如果在反序列化时得到,请添加到类的顶部。NullReferenceException[Serializable]

.任何其他问题,请验证您的 json 是否有效。在此处转到此站点并粘贴 json。它应该显示 json 是否有效。它还应该使用 Json 生成正确的类。只需确保从每个变量中删除 remove,并添加到生成的每个类的顶部即可。{ get; set; }[Serializable]


Newtonsoft.Json:

如果出于某种原因必须使用 Newtonsoft.Json,那么从 2022 年 2 月起,现在可以直接从 Unity 获取它:[email protected]。只需通过包管理器添加即可。有关详细信息,请参阅通过 kalle (jag) 通过 UPM 安装官方版com.unity.nuget.newtonsoft-json

您还可以查看 SaladLab / 的 Unity 分叉版本 请注意,如果使用某些功能,可能会遇到崩溃。小心。


要回答您的问题,请执行以下操作:

您的原始数据是

 [{"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]是您的第三个数据

或类内的数据用 、 、 ......playerInstance[0].playerLocplayerInstance[1].playerLocplayerInstance[2].playerLoc

您可以使用在访问之前检查长度。playerInstance.Length

注意:从类中删除。如果有,它将不起作用。Unity 不适用于定义为属性类成员。{ get; set; }player{ get; set; }JsonUtility

评论

2赞 Programmer 3/27/2016
看看我上面发布的代码。它向您展示了使用 .我忘了告诉你从班级中删除。如果有,它将不起作用。将您的班级与我上面发布的班级进行比较,您就会明白我在说什么。JsonUtility.FromJson{ get; set; }player{ get; set; }player
1赞 Programmer 3/28/2016
没关系。当Unity添加对数组的支持时,我将对其进行编辑(很快),因此您将不再需要该Helper类。
3赞 Everts 2/3/2017
我不会说“忘记所有第三方库”。JsonUtility 有局限性。它不会返回可以对其执行操作的 JSON 对象。例如,我得到一个 json 文件,并想检查“成功”密钥是否可用。做不到。JsonUtility 要求使用者知道 json 文件的确切内容。此外,没有字典转换器。所以它做了一些好事,但仍然需要使用第三方。
3赞 Programmer 3/9/2017
用。没事的。如果你用它创建 Json,你也可以用它读取 json,而无需额外的步骤。您可能需要做额外事情的唯一时间是,如果您从服务器接收 json 数组,并且该数组包含在解决方案中,则在我的答案中。另一种没有的方法是将类放在另一个类中,然后使其成为 .这对大多数人都有效。如果您正在寻找一种保存和加载游戏数据的方法,请参阅内容。只需一行代码即可加载和保存。JsonHelperJsonHelperList
1赞 derHugo 5/17/2021
请注意,在较新版本的 Newtonsoft JSON 中,通过包管理器作为半“内置”!它更强大,例如支持:属性、字典、嵌套数组等
3赞 Myan 12/5/2016 #4

你必须添加到类中,像这样:[System.Serializable]PlayerItem

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}
24赞 Narottam Goyal 9/26/2017 #5

假设你得到了一个这样的 JSON

[
    {
        "type": "qrcode",
        "symbol": [
            {
                "seq": 0,
                "data": "HelloWorld9887725216",
                "error": null
            }
        ]
    }
]

要在 Unity 中解析上述 JSON,您可以像这样创建 JSON 模型。

[System.Serializable]
public class QrCodeResult
{
    public QRCodeData[] result;
}

[System.Serializable]
public class Symbol
{
    public int seq;
    public string data;
    public string error;
}

[System.Serializable]
public class QRCodeData
{
    public string type;
    public Symbol[] symbol;
}

然后简单地按以下方式解析...

var myObject = JsonUtility.FromJson<QrCodeResult>("{\"result\":" + jsonString.ToString() + "}");

现在您可以根据需要修改 JSON/CODE。https://docs.unity3d.com/Manual/JSONSerialization.html

评论

0赞 Gennon 5/14/2018
这实际上效果很好,让它与像 Symbol 这样的类一起工作,而 Symbol 也不是数组。
4赞 Jean-Michaël Celerier 10/6/2018
我正在用 unity 2018 尝试这个,但这不起作用:数组没有被解析
0赞 Towerss 4/29/2019
在 Unity 2018 和 2019 中使用。效果很好。访问数组数据,例如: 或 或Debug.Log(myObject.result[0].symbol[0].data);for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }foreach (var item in myObject.result) { Debug.Log(item.type); }
0赞 Junaid Pathan 5/15/2019
@Narottam Goyal,您的方法在某些情况下不起作用,对于初学者来说也是一个非常困难的解决方案,请在此线程链接上参考我的此答案
0赞 derHugo 6/7/2019
@JunedKhanMomin你的答案基本相同,但没有解决这样一个事实,即这里的这个问题是关于JSON数据中的根级数组的。一般来说,你应该参考程序员的回答,它更详细。
0赞 Junaid Pathan 5/15/2019 #6

要读取 JSON 文件,请参阅以下简单示例

您的 JSON 文件 (StreamingAssets/Player.json)

{
    "Name": "MyName",
    "Level": 4
}

C# 脚本

public class Demo
{
    public void ReadJSON()
    {
        string path = Application.streamingAssetsPath + "/Player.json";
        string JSONString = File.ReadAllText(path);
        Player player = JsonUtility.FromJson<Player>(JSONString);
        Debug.Log(player.Name);
    }
}

[System.Serializable]
public class Player
{
    public string Name;
    public int Level;
}

评论

2赞 derHugo 7/1/2019
阵列呢?这个答案增加了什么,而 3 年前的公认答案中还没有实现?
0赞 Ruzihm 9/24/2020
@derHugo它包括一个我认为有帮助的电话,没有其他答案提到:)File.ReadAllText
1赞 derHugo 9/24/2020
@Ruzihm,之所以没有提到其他答案,是因为这个问题的范围是如何(反)序列化.不是如何做 FileIO ;)
0赞 Seyed Morteza Kamali 10/13/2019 #7

你可以只使用添加到你的项目并使用下面的脚本Newtonsoft.JsonNewtonsoft.dll

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
       var myjson = JsonConvert.SerializeObject(person);

        print(myjson);

    }
}

enter image description here

另一种解决方案是使用 JsonHelper

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
        var myjson = JsonHelper.ToJson(person);

        print(myjson);

    }
}

enter image description here

评论

2赞 Rose 11/22/2020
请注意,例如,当您在 android 上构建时,newtonsoft 似乎无法在 Unity 中工作。不过,它将在unity编辑器上运行。在这种情况下,似乎建议使用 newtonsoft 的 unity 分支 stackoverflow.com/questions/59194154/......
-1赞 Gara 1/2/2020 #8

如果您使用的是 Vector3,这就是我所做的

1-我创建了一个类,将其命名为Player

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Player
{
    public Vector3[] Position;

}

2-那我这样称呼它

if ( _ispressed == true)
        {
            Player playerInstance = new Player();
            playerInstance.Position = newPos;
            string jsonData = JsonUtility.ToJson(playerInstance);

            reference.Child("Position" + Random.Range(0, 1000000)).SetRawJsonValueAsync(jsonData);
            Debug.Log(jsonData);
            _ispressed = false;
        }

3-这就是结果

“位置”:[ {“x”:-2.8567452430725099,“y”:-2.4323320388793947,“z”:0.0}]}

5赞 Justin Meiners 6/27/2020 #9

Unity <= 2019 年

Narottam Goyal 有一个好主意,将数组包装在一个 json 对象中,然后反序列化为一个结构体。 下面使用泛型来解决所有类型的数组的问题,而不是每次都创建一个新类。

[System.Serializable]
private struct JsonArrayWrapper<T> {
    public T wrap_result;
}

public static T ParseJsonArray<T>(string json) {
    var temp = JsonUtility.FromJson<JsonArrayWrapper<T>>("{\"wrap_result\":" + json + "}");
    return temp.wrap_result;
}

它可以通过以下方式使用:

string[] options = ParseJsonArray<string[]>(someArrayOfStringsJson);

Unity 2020 大会

在 Unity 2020 中,有一个官方的 newtonsoft 包,它是一个更好的 json 库。

评论

5赞 R2RT 9/18/2020
您提供的链接已失效,但此链接被列为相关文章:docs.unity3d.com/Packages/[email protected]/...,并注明:“这是一个用于内部Unity开发项目的包,因此不支持此包。使用风险自负。
0赞 david.pfx 4/6/2021
第一个解决方案仍然有效吗?我得到的只是wrap_result的 null 值。
0赞 Justin Meiners 4/9/2021
@david.pfx 有一个错别字已经修复,现在怎么样?
0赞 david.pfx 4/10/2021
对不起,无法测试它,切换到 Newtonsoft 以保持进展。但是当我有时间时,我会再试一次——我真的不想添加不必要的依赖关系。
2赞 Peppe L-G 9/2/2021
多亏了这个包,现在终于有了支持Unity多态性的序列化。在 Unity 中,只需打开“包管理器”窗口,然后选择按名称添加包,并提供名称。com.unity.nuget.newtonsoft-json
0赞 seth 7/16/2023 #10

如果你来这里寻找如何使用 JsonUtility 序列化列表,而不需要任何额外的包,请继续阅读。

[System.Serializable]
public class JsonableListWrapper<T>
{
    public List<T> list;
    public JsonableListWrapper(List<T> list) => this.list = list;
}

用法示例:

List<string> stringList = new List<string>(){"one","two","three"};
// To Json
string stringListAsJson = JsonUtility.ToJson(new JsonListWrapper<string>(stringList));
// From Json
List<string> stringListFromJson = JsonUtility.FromJson<JsonListWrapper<string>>(stringListAsJson).list;

归功于这个线程的唯一缘故:https://forum.unity.com/threads/jsonutilities-tojson-with-list-string-not-working-as-expected.722783/

似乎你不能直接序列化/反序列化一个列表,但如果它是类的属性,你可以。在我个人的情况下,我将字符串类型替换为自定义类的类型,效果很好。