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

dil*_*3pm 81 c# json unity-game-engine

我有一个从PHP文件发送到Unity的项目列表WWW.

WWW.text样子:

[
    {
        "playerId": "1",
        "playerLoc": "Powai"
    },
    {
        "playerId": "2",
        "playerLoc": "Andheri"
    },
    {
        "playerId": "3",
        "playerLoc": "Churchgate"
    }
]
Run Code Online (Sandbox Code Playgroud)

[]从哪里修剪额外的string.当我尝试使用它解析它时Boomlagoon.JSON,只检索第一个对象.我发现我已经到deserialize()了列表并导入了MiniJSON.

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

我正在使用的课程是

public class player
{
    public string playerId { get; set; }
    public string playerLoc { get; set; }
    public string playerNick { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

修剪后[]我可以使用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));
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Pro*_*mer 199

5.3.3更新之后,Unity将JsonUtility添加到他们的API中.忘掉所有第三方库,除非你做的更复杂.JsonUtility比其他Json库更快.更新到Unity 5.3.3或更高版本,然后尝试以下解决方案.

JsonUtility是一个轻量级的API.仅支持简单类型.它支持的集合,如字典.一个例外是List.它支持ListList阵列!

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

要序列化的示例类:

[Serializable]
public class Player
{
    public string playerId;
    public string playerLoc;
    public string playerNick;
}
Run Code Online (Sandbox Code Playgroud)

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

序列化A部分:

使用该public static string 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);
Run Code Online (Sandbox Code Playgroud)

输出:

{"playerId":"8484239823","playerLoc":"Powai","playerNick":"Random Nick"}
Run Code Online (Sandbox Code Playgroud)

序列化B部分:

使用public static string 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);
Run Code Online (Sandbox Code Playgroud)

输出:

{
    "playerId": "8484239823",
    "playerLoc": "Powai",
    "playerNick": "Random Nick"
}
Run Code Online (Sandbox Code Playgroud)

反序列化A部分:

使用public static T FromJson(string json);方法重载反序列化 json .

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

反序列化B部分:

使用public static object 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);
Run Code Online (Sandbox Code Playgroud)

反序列化C部分:

使用该public static void FromJsonOverwrite(string json, object objectToOverwrite);方法反序列化 json .当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);
}
Run Code Online (Sandbox Code Playgroud)

2.多个数据(ARRAY JSON)

您的Json包含多个数据对象.例如playerId出现不止一次.Unity的JsonUtility不支持阵列,因为它仍然是新的,但你可以使用一个辅助类从这个人得到阵列与合作JsonUtility.

创建一个名为的类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;
    }
}
Run Code Online (Sandbox Code Playgroud)

序列化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);
Run Code Online (Sandbox Code Playgroud)

输出:

{
    "Items": [
        {
            "playerId": "8484239823",
            "playerLoc": "Powai",
            "playerNick": "Random Nick"
        },
        {
            "playerId": "512343283",
            "playerLoc": "User2",
            "playerNick": "Rand Nick 2"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

反序列化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);
Run Code Online (Sandbox Code Playgroud)

输出:

博万

用户2


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

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

我为此做了一个简单的功能:

string fixJson(string value)
{
    value = "{\"Items\":" + value + "}";
    return value;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用它:

string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);
Run Code Online (Sandbox Code Playgroud)

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" : "$"}
}
Run Code Online (Sandbox Code Playgroud)

Unity's JsonUtility不支持这个,因为"15m"属性以数字开头.类变量不能以整数开头.

SimpleJSON.cs从Unity的wiki下载.

要获得美元的"15m"财产:

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

要获得ISK的"15m"财产:

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

要获得新西兰元的"15米"房产:

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

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


4.TROUBLESHOOTING JsonUtility:

序列化时遇到的问题JsonUtility.ToJson

得到空字符串或" {}" 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]到类的顶部.

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


Newtonsoft.Json:

如果由于某种原因必须使用Newtonsoft.Json,那么在这里查看Unity的分叉版本.请注意,如果使用某些功能,您可能会遇到崩溃.小心.


回答你的问题:

你原来的数据是

 [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]
Run Code Online (Sandbox Code Playgroud)

{"Items":在它前面添加然后在它的末尾添加 .}

代码来做到这一点:

serviceData = "{\"Items\":" + serviceData + "}";
Run Code Online (Sandbox Code Playgroud)

现在你有:

 {"Items":[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]}
Run Code Online (Sandbox Code Playgroud)

要将php中的多个数据序列化为数组,您现在可以执行此操作

public player[] playerInstance;
playerInstance = JsonHelper.FromJson<player>(serviceData);
Run Code Online (Sandbox Code Playgroud)

playerInstance[0] 是你的第一个数据

playerInstance[1] 是你的第二个数据

playerInstance[2] 是你的第三个数据

或里面的类数据与playerInstance[0].playerLoc,playerInstance[1].playerLoc,playerInstance[2].playerLoc......

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

注意: 从班级中删除 .如果你有,它不会工作.Unity的确实与被定义为类成员的工作性质.{ get; set; }player{ get; set; }JsonUtility

  • 看看我上面发布的代码。它显示了三种使用`JsonUtility.FromJson`的方法。我忘了告诉你删除`{get; 组; }`来自`player`类。如果您有`{get; 组; }`,它将无法正常工作。将您的“玩家”课程与我上面发布的课程进行比较,您将理解我的意思。 (2认同)
  • 我不会说“忘记所有 3rd 方库”。JsonUtility 有局限性。它不会返回您可以对其执行操作的 JSON 对象。例如,我得到一个 json 文件并想检查“成功”键是否可用。做不到。JsonUtility 要求使用者知道 json 文件的确切内容。此外,没有字典转换器。所以它做了一些好事,但仍然需要使用 3rd 方。 (2认同)
  • 使用`JsonHelper`.没关系.如果你用它创建Json,你也可以用它来读取json而无需额外的步骤.你可能需要做额外的事情的唯一一次是你从服务器接收json数组,并且解决方案中包含的是我的答案.没有`JsonHelper`的另一种方法是将类放在另一个类中,然后使它成为`List`.这对大多数人来说都很有用.如果您正在寻找保存和加载游戏数据的方法,请参阅[this](http://stackoverflow.com/a/40966346/3785314).*您使用一行代码加载并保存.* (2认同)

Nar*_*yal 15

假设你有一个像这样的JSON

[
    {
        "type": "qrcode",
        "symbol": [
            {
                "seq": 0,
                "data": "HelloWorld9887725216",
                "error": null
            }
        ]
    }
]
Run Code Online (Sandbox Code Playgroud)

要统一解析上面的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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我正在尝试使用Unity 2018进行此操作,但这无法正常工作:数组未解析 (4认同)

Jus*_*ers 5

团结 <= 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;
}
Run Code Online (Sandbox Code Playgroud)

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

string[] options = ParseJsonArray<string[]>(someArrayOfStringsJson);
Run Code Online (Sandbox Code Playgroud)

团结2020

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

  • 您提供的链接已失效,但此链接被列为相关文章:https://docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@2.0/manual/index.html,并附注:“This是一个用于内部 Unity 开发项目的包,因此不支持此包。使用风险自负。” (5认同)
  • 多亏了这个包,现在终于在 Unity 中获得了支持多态性的序列化。在 Unity 中,只需打开“包管理器”窗口,然后选择按名称添加包,并提供“com.unity.nuget.newtonsoft-json”作为名称。 (2认同)