我正在为 Unity 构建一个通用保存系统。作为序列化器,我使用 Json.NET。
主要数据容器是一个包含
Dictionary<string/*dataKey*/, ISaveableData/*data to be saved*/>
的类。因为 ISaveableData
是一个接口,所以我使用具体类型作为 json 中的键。这样我就知道加载时数据需要反序列化成哪种类型。
一切工作正常,直到我尝试将数据反序列化到具体类中。我创建了一个自定义转换器来处理反序列化,但我似乎出错了。
我当前的自定义转换器中的
Read()
方法看起来像这样:
public override Data ReadJson(JsonReader reader, Type objectType, Data existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
//load json object
JObject jObject = JObject.Load(reader);
Data data = new();
foreach (JToken token in jObject.Children())
{
//get key
string key = token.Path; //in my example 'key' will either be "DataTypeOne" or "DataTypeTwo"
//determine correct type, based on the key (pseudo-code, this step works fine)
Type type = GetTypeByKey(key);
//now I know the type, I want to deserialize the token into an instance of the specified type
//this fails with error 'Unexpected token while deserializing object: PropertyName. Path 'DataTypeOne'
object deserializedInstance = token.ToObject(type, serializer);
//add to data
data.Add((ISaveable)deserializedInstance);
}
return data;
}
json 看起来像这样:
{
"SaveSlotName": "Example",
"Data": {
"DataTypeOne": {
"SomeValue": 5
},
"DataTypeTwo": {
"SomeOtherValue": "Hello"
}
}
}
为什么
JToken.ToObject(type, serializer)
会抛出错误? Read()
方法应该如何使用?
我发现了问题。
我尝试反序列化令牌,但我需要反序列化令牌的值。
这是新的
Read()
方法。也许这对遇到同样问题的其他人有帮助。
public override Data ReadJson(JsonReader reader, Type objectType, Data existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
//load json object
JObject jObject = JObject.Load(reader);
Data data = new();
foreach (JToken token in jObject.Children())
{
//cast token to property
var property = (JProperty)token;
//get key
string key = token.Path; //in my example 'key' will either be "DataTypeOne" or "DataTypeTwo"
//determine correct type, based on the key (pseudo-code, this step works fine)
Type type = GetTypeByKey(key);
//get the value of this property
JToken value = property.Value;
//now I know the type and the property value and can deserialize it into an instance of the specified type
object deserializedInstance = value.ToObject(type, serializer);
//add to data
data.Add((ISaveable)deserializedInstance);
}
return data;
}