使用 Newtonsoft 反序列化只有 getter 的摘要 class
Deserialize an abstract class that has only a getter using Newtonsoft
我正在尝试反序列化 JSON 我得到:
[
{
"Name":"0",
"Health":0,
"TypeName":"SpellInfo",
"Info":{
"Effect":1,
"EffectAmount":4
}
},
{
"Name":"1",
"Health":0,
"TypeName":"MonsterInfo",
"Info":{
"Health":10,
"AttackDamage":10
}
},
...
...
]
创建了一个 class 来处理 JSON:
[System.Serializable]
public class CardDataStructure
{
public string Name;
public int Health;
public string TypeName;
public Info Info;
}
我设法获得了我需要的所有信息,但 Info.根据我所做的研究,我从 link - https://blog.codeinside.eu/2015/03/30/json-dotnet-deserialize-to-abstract-class-or-interface/ 创建了一个 JsonConverter
这实际上非常接近,
public class InfoConvert: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Info));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo.ToString().Contains("Effect"))
{
if (jo["Effect"].Value<string>() is string)
return jo.ToObject<SpellInfo>(serializer);
}
if (jo.ToString().Contains("Health"))
{
if (jo["Health"].Value<string>() is string)
return jo.ToObject<MonsterInfo>(serializer);
}
return null;
}
}
(最好通过 'typename' 找到它,但我不知道该怎么做,所以选择了一些简单的方法)
当检查 'jo' 时,属性在那里并转到正确的 class 但是一旦离开转换器我得到默认属性而不是一旦转换器显示。
我找不到 link 但在 Newtonsoft 文档上它说某处存在反序列化抽象 class 的问题,如果抽象 class 没有 public setter.
monsterinfo 和 spellinfo 都继承自 info:
[Serializable]
public abstract class Info
{
}
monsterinfo
和spellinfo
看起来基本一样。问题是他们没有 public setter,我现在不能更改它们。
{
[Serializable]
public class MonsterInfo: Info
{
[SerializeField]
private int m_Health;
public int Health => m_Health;
[SerializeField]
private int m_AttackDamage;
public int AttackDamage => m_AttackDamage;
}
}
因此,在尝试反序列化 JSON 时:
string contents = File.ReadAllText(source);
contents = "{\"cards\":" + contents + "}";
JsonConverter[] converters = { new InfoConvert() };
cardsData = JsonConvert.DeserializeObject<Cards>(contents, new JsonSerializerSettings() {
Converters = converters, NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.Auto});
*Cards 是 CardDataStructure 的列表
是否有可能在不给它们 public setter 的情况下获取 Info 中的数据?
我得到的最好的是 JSON 中的所有数据和一个空的 Monster/Spell Info.
最后我只需要解析我得到的 json,但是当 'name'、'health'、'typeinfo' 被正确解析时,信息是总是一个用 0 填充的空对象。
编辑:更正了一些内容。
你应该像这个家伙那样做:
用于检测类型或反序列化的标记接口
一个容器class
Dto classes
//marker interface
public interface Info { }
public class HealthInfo : Info
{
public int MoreHealth { set; get; }
public int AttackDamage { set; get; }
}
public class SpellInfo : Info
{
public int Effect { set; get; }
public int EffectAmount { set; get; }
}
public class Card<T> where T : Info
{
public Card(string name, int health, T info)
{
this.Info = info;
this.Name = name;
this.Health = health;
}
public T Info { private set; get; }
public string Name { set; get; }
public int Health { set; get; }
}
public class InfoConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(Card<Info>))
{
return true;
}
return false;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
if (jObject.ContainsKey("TypeName"))
{
string typeName = jObject["TypeName"]?.ToString()?.Trim()?.ToLower();
if (typeName?.Equals("monsterinfo") == true)
{
Card<HealthInfo> deseerialized = jObject.ToObject<Card<HealthInfo>>();
return new Card<Info>(deseerialized.Name, deseerialized.Health, deseerialized.Info);
}
if (typeName?.Equals("spellinfo") == true)
{
string json = jObject.ToString();
Card<SpellInfo> deseerialized = jObject.ToObject<Card<SpellInfo>>();
return new Card<Info>(deseerialized.Name, deseerialized.Health, deseerialized.Info);
}
}
return null;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
你应该执行:
List<Card<Info>> list = JsonConvert.DeserializeObject<List<Card<Info>>>(jsonText, new InfoConverter());
我正在尝试反序列化 JSON 我得到:
[
{
"Name":"0",
"Health":0,
"TypeName":"SpellInfo",
"Info":{
"Effect":1,
"EffectAmount":4
}
},
{
"Name":"1",
"Health":0,
"TypeName":"MonsterInfo",
"Info":{
"Health":10,
"AttackDamage":10
}
},
...
...
]
创建了一个 class 来处理 JSON:
[System.Serializable]
public class CardDataStructure
{
public string Name;
public int Health;
public string TypeName;
public Info Info;
}
我设法获得了我需要的所有信息,但 Info.根据我所做的研究,我从 link - https://blog.codeinside.eu/2015/03/30/json-dotnet-deserialize-to-abstract-class-or-interface/ 创建了一个 JsonConverter
这实际上非常接近,
public class InfoConvert: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(Info));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo.ToString().Contains("Effect"))
{
if (jo["Effect"].Value<string>() is string)
return jo.ToObject<SpellInfo>(serializer);
}
if (jo.ToString().Contains("Health"))
{
if (jo["Health"].Value<string>() is string)
return jo.ToObject<MonsterInfo>(serializer);
}
return null;
}
}
(最好通过 'typename' 找到它,但我不知道该怎么做,所以选择了一些简单的方法)
当检查 'jo' 时,属性在那里并转到正确的 class 但是一旦离开转换器我得到默认属性而不是一旦转换器显示。
我找不到 link 但在 Newtonsoft 文档上它说某处存在反序列化抽象 class 的问题,如果抽象 class 没有 public setter.
monsterinfo 和 spellinfo 都继承自 info:
[Serializable]
public abstract class Info
{
}
monsterinfo
和spellinfo
看起来基本一样。问题是他们没有 public setter,我现在不能更改它们。
{
[Serializable]
public class MonsterInfo: Info
{
[SerializeField]
private int m_Health;
public int Health => m_Health;
[SerializeField]
private int m_AttackDamage;
public int AttackDamage => m_AttackDamage;
}
}
因此,在尝试反序列化 JSON 时:
string contents = File.ReadAllText(source);
contents = "{\"cards\":" + contents + "}";
JsonConverter[] converters = { new InfoConvert() };
cardsData = JsonConvert.DeserializeObject<Cards>(contents, new JsonSerializerSettings() {
Converters = converters, NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.Auto});
*Cards 是 CardDataStructure 的列表
是否有可能在不给它们 public setter 的情况下获取 Info 中的数据? 我得到的最好的是 JSON 中的所有数据和一个空的 Monster/Spell Info.
最后我只需要解析我得到的 json,但是当 'name'、'health'、'typeinfo' 被正确解析时,信息是总是一个用 0 填充的空对象。
编辑:更正了一些内容。
你应该像这个家伙那样做:
用于检测类型或反序列化的标记接口
一个容器class
Dto classes
//marker interface public interface Info { } public class HealthInfo : Info { public int MoreHealth { set; get; } public int AttackDamage { set; get; } } public class SpellInfo : Info { public int Effect { set; get; } public int EffectAmount { set; get; } } public class Card<T> where T : Info { public Card(string name, int health, T info) { this.Info = info; this.Name = name; this.Health = health; } public T Info { private set; get; } public string Name { set; get; } public int Health { set; get; } } public class InfoConverter : JsonConverter { public override bool CanConvert(Type objectType) { if (objectType == typeof(Card<Info>)) { return true; } return false; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jObject = JObject.Load(reader); if (jObject.ContainsKey("TypeName")) { string typeName = jObject["TypeName"]?.ToString()?.Trim()?.ToLower(); if (typeName?.Equals("monsterinfo") == true) { Card<HealthInfo> deseerialized = jObject.ToObject<Card<HealthInfo>>(); return new Card<Info>(deseerialized.Name, deseerialized.Health, deseerialized.Info); } if (typeName?.Equals("spellinfo") == true) { string json = jObject.ToString(); Card<SpellInfo> deseerialized = jObject.ToObject<Card<SpellInfo>>(); return new Card<Info>(deseerialized.Name, deseerialized.Health, deseerialized.Info); } } return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
你应该执行:
List<Card<Info>> list = JsonConvert.DeserializeObject<List<Card<Info>>>(jsonText, new InfoConverter());