我正在开发一款名为UserInfo的游戏。

UserInfo类内部,有一个public List<Lineup> lineups变量。

并且Lineup包含public Dictionary<Vector2Int, Collection> cardLocations

我的问题是,JsonConvert.SerializeObject可以正确产生所需的结果,但是当我执行JsonConvert.DeserializeObject<UserInfo>时,Vector2Int仍然是像"(x, y)"这样的字符串。

我该如何解决?

我写了一个JsonConverter进行转换,并使用了

JsonConvert.SerializeObject(userInfo, Formatting.Indented, new Vec2Converter())


用于序列化和

JsonConvert.DeserializeObject<UserInfo>(json, new Vec2Converter())


反序列化,但这是行不通的。

这是我的JsonConverter脚本:

using Newtonsoft.Json;
using UnityEngine;
using System;

public class Vec2Converter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value.ToString());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var vector2Int = serializer.Deserialize<Vector2Int>(reader);
        Debug.Log(vector2Int);
        return vector2Int;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Vector2Int);
    }
}


另一个奇怪的事情是,当我尝试将Vector2Int更改为其他数据结构(例如LineupDictionary<Vector2Int, Collection>)时,单击播放时Unity退出。我改回来后,一切正常。好的表示它没有退出,但仍然给我错误消息。

忘记输入错误消息:ArgumentException: Could not cast or convert from System.String to UnityEngine.Vector2Int

这是课程。

public class UserInfo {
    public string username;
    public int playerID;
    public List<Collection> collection = new List<Collection>();
    public List<Lineup> lineups = new List<Lineup>(); // Here is the problem
    public Dictionary<string, int> contracts = new Dictionary<string, int>();
    public int coins = 0;
    public int rank = 0;
    public int lastLineupSelected = -1;
    public int winsToday = 0;
    public Stats total = new Stats();
    public Dictionary<string, Stats> boardResults = new Dictionary<string, Stats>();
    public List<Mission> missions;
    public string preferredBoard = "Standard Board";
    public string lastModeSelected = "";
    public int gameID;
    public bool missionSwitched = false;
}

public class Lineup
{
    public Dictionary<Vector2Int, Collection> cardLocations;  // Here is the problem
    public List<Tactic> tactics;
    public string boardName;
    public string lineupName;
    public string general;
    public bool complete;
}

public class Collection
{
    public string name = "";
    public string type = "";
    public int count = 1;
    public int health = 0;
    public int oreCost = 0;
}

最佳答案

JsonConverter派生的自定义序列化器需要做更多的工作,并且几乎没有错误。首先,请注意,您正在尝试对DictionaryVector2Int进行序列化/反序列化,而不仅仅是Vector2Int变量。

是这样的:

public Dictionary<Vector2Int, Collection> cardLocations.




public Vector2Int cardLocations;




由于上述声明,您的override bool CanConvert(Type objectType)函数应检查typeof(Dictionary<Vector2Int, Collection>)而不是typeof(Vector2Int)。另外,您还需要添加检查以确定何时运行自定义反序列化器。

序列化:

1.在序列化json的WriteJson函数中,您只需要自定义引发异常的Dictionary<Vector2Int, Collection>部分,因此请确保自定义代码仅在类型为Dictionary<Vector2Int, Collection>时运行。您可以通过将代码放入if (value is Dictionary<Vector2Int, Collection>)中来实现。

2.从第二个参数中获取字典进行序列化。调用writer.WriteStartArray(),以便将每个值写为数组。现在,遍历Dictionary,用writer.WriteValue(key)编写密钥,然后用serializer.Serialize(writer, entry.Value);编写值。

3.在循环调用writer.WriteStartArray();之后/之外,然后从该函数返回。

如果#1中的if (value is Dictionary<Vector2Int, Collection>)false,则只需调用writer.WriteStartObject(),然后再调用writer.WriteEndObject()



反序列化:

4,确定何时运行自定义反序列化器

序列化时,我们在#1中使用if (value is Dictionary<Vector2Int, Collection>)来确定是否应运行自定义序列化程序代码,但对于反序列化,我们使用if (reader.TokenType == JsonToken.StartArray)来确定是否已到达在ReadJson中进行自定义序列化的数组部分功能。

5.使用JArray.Load(reader);获取我们序列化的阵列数据。在返回的数组中,其中的第一个元素是Dictionary中的键,第二个元素是Dictionary中的值。第三个元素是Dictionary中的第二个键。第四个元素是Dictionary中的第二个值,依此类推。

6.分隔JArray中的键和值。

为了简化此过程,请按JArray而不是2循环1增量。通过增加2,可以很容易地使用JArray[loop + 0]检索密钥,并且可以使用JArray[loop + 1]在相同的循环中检索值。

for (int i = 0; i < jArray.Count; i += 2)
{
    //Key
    string key = jArray[i + 0].ToString();
    //Value
    string value = jArray[i + 1].ToString();
}


7.以Vector2Int格式获取密钥。

只需使用Vector2Int将密钥从#6反序列化为JsonConvert.DeserializeObject<Vector2Int>(key)

8.以Collection格式获取值。

只需使用Collection将#6中的值反序列化为JsonConvert.DeserializeObject<Collection>(value)

9,重建数据

创建Dictionary<Vector2Int, Collection>的新实例,然后将#7中的键和#8中的值添加到它,然后从ReadJson函数返回它。

如果#4中的if (reader.TokenType == JsonToken.StartArray)false,只需从Dictionary<Vector2Int, Collection>函数创建并返回ReadJson的新实例,而无需向其添加键或值。

class Vec2DictionaryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Dictionary<Vector2Int, Collection>).IsAssignableFrom(objectType);
    }

    //Deserialize json to an Object
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        //Debug.Log("De-serializing!");
        if (reader.TokenType == JsonToken.StartArray)
        {
            // Load JArray from stream
            JArray jArray = JArray.Load(reader);

            //Where to re-create the json data into
            Dictionary<Vector2Int, Collection> dict = new Dictionary<Vector2Int, Collection>();

            if (jArray == null || jArray.Count < 2)
            {
                return dict;
            }

            //Do the loop faster with +=2
            for (int i = 0; i < jArray.Count; i += 2)
            {
                //first item = key
                string firstData = jArray[i + 0].ToString();
                //second item = value
                string secondData = jArray[i + 1].ToString();

                //Create Vector2Int key data
                Vector2Int vect = JsonConvert.DeserializeObject<Vector2Int>(firstData);

                //Create Collection value data
                Collection values = JsonConvert.DeserializeObject<Collection>(secondData);

                //Add both Key and Value to the Dictionary if key doesnt exit yet
                if (!dict.ContainsKey(vect))
                    dict.Add(vect, values);
            }
            //Return the Dictionary result
            return dict;
        }
        return new Dictionary<Vector2Int, Collection>();
    }

    //SerializeObject to Json
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        //Debug.Log("Serializing!");
        if (value is Dictionary<Vector2Int, Collection>)
        {
            //Get the Data to serialize
            Dictionary<Vector2Int, Collection> dict = (Dictionary<Vector2Int, Collection>)value;

            //Loop over the Dictionary array and write each one
            writer.WriteStartArray();
            foreach (KeyValuePair<Vector2Int, Collection> entry in dict)
            {
                //Write Key (Vector)
                serializer.Serialize(writer, entry.Key);
                //Write Value (Collection)
                serializer.Serialize(writer, entry.Value);
            }
            writer.WriteEndArray();
            return;
        }
        writer.WriteStartObject();
        writer.WriteEndObject();
    }
}


用法:

连载

string json = JsonConvert.SerializeObject(userInfo, new Vec2DictionaryConverter());


反序列化

UserInfo obj = JsonConvert.DeserializeObject<UserInfo>(json, new Vec2DictionaryConverter());

07-26 08:39