将 JSON 包反序列化为具有自定义属性名称的类
Posted
技术标签:
【中文标题】将 JSON 包反序列化为具有自定义属性名称的类【英文标题】:Deserializing a JSON package to a class with custom property names 【发布时间】:2021-06-06 07:33:42 【问题描述】:问题
我从服务器接收到格式为 "A": 'Pelle', "B": 55, "C": 5.5
的 JSON 包,需要将其映射到以下格式的实体类:
class EntityAttributes
public string Name get; set;
public int Level get; set;
public float Strength get; set;
JSON中的属性名“A”、“B”、“C”应按照如下类进行映射:
class Constants
public const byte NAME = 65; // ASCII "A"
public const byte LEVEL = 66; // ASCII "B"
public const byte STRENGTH = 67; // ASCII "C"
其中 65 是“A”的 ASCII 字节表示,“B”的 66 和“C”的 67。
我被困在哪里(我不知道这是否是正确的方法):
我一直在尝试使用JSON NET FOR UNITY,它允许您使用自定义名称将 JSON 反序列化为一个类:
class EntityAttributes
[[JsonProperty("A")]]
public string Name get; set;
[[JsonProperty("B")]]
public int Level get; set;
[[JsonProperty("C")]]
public float Strength get; set;
但是,我不想在注释中硬编码“A”、“B”和“C”,因为这些将来可能会发生变化。也不可能(afaik)在装饰器中从字节转换为字符串,因为只允许 常量表达式。
知道我应该如何解决这个问题吗?
【问题讨论】:
为什么你的常量不能简单地是字符串? 常量的服务器内部表示是字节。必须同步服务器常量和客户端常量已经有点麻烦了,在此之上添加一个字节 -> 字符转换并不理想。 为什么服务器常量不能是字符串? / 为什么服务端不能有常量字节和字符串之间的非常量映射? 也许可以,但是改变内部服务器结构,使常量必须匹配客户端内部结构的方法名称真的有意义吗? 好吧,在一方面,你必须这样做..要么服务器必须提供客户端所期望的客户端,要么必须处理服务器提供的任何东西......无论哪种方式,如果一个一边改变了,另一边也必须改变。可能没有办法解决这个问题 【参考方案1】:这听起来有点像主要问题是您的字段名称必须保持不变 - 您不想要什么。
由于您的属性足够简单/基本,您可以改用很久以前由 Units 社区中的某个人编写的 SimpleJson
;)您只需在项目的任何位置创建该文件。
最大的优势:它可以使用完全动态的字段名称,因此您可以轻松地制作它,例如
public static class Constants
public const byte NAME = 65;
public const byte LEVEL = 66;
public const byte STRENGTH = 67;
然后做例如
class EntityAttributes
public readonly string Name get;set;;
public readonly int Level get;set;
public readonly float Strength get;set;
public EntityAttributes(string name, int level, float strength)
Name = name;
Level = level;
Strength = strength;
现在,无论您最初将 JSON 直接解析为哪种类型,您都不会再使用该类型了。相反,你会做类似的事情,例如
var root = JSON.Parse(jsonString);
var item = new EntityAttributes (
root[Encoding.ASCII.GetString(new [](Constants.NAME)].Value,
root[Encoding.ASCII.GetString(new []Constants.LEVEL)].AsInt(),
root[Encoding.ASCII.GetString(new []Constants.STRENGTH)].AsFloat()
);
请注意,当然,无论哪种方式,您仍然必须正确设置这些常量字节值。
所以在我个人看来,我仍然认为你可以/应该简单地使用
public static class Constants
public const string NAME = "A";
public const string LEVEL = "B";
public const string STRENGTH = "C";
那你就不会有那个麻烦了。您的服务器必须提供客户端期望的任何结构,或者客户端必须处理服务器提供的任何结构。无论哪种方式,如果一侧发生更改,另一侧也必须更改。
注意:在智能手机上输入,但我希望思路清晰
【讨论】:
【参考方案2】:您可以创建一个自定义JsonConverter 来解决这个问题:
class EntityAttributesConverter : JsonConverter
public override bool CanConvert(Type objectType)
return objectType == typeof(EntityAttributes);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
JObject jo = JObject.Load(reader);
return new EntityAttributes
Name = GetValue<string>(jo, Constants.NAME),
Level = GetValue<int>(jo, Constants.LEVEL),
Strength = GetValue<float>(jo, Constants.STRENGTH)
;
private static T GetValue<T>(JObject jo, byte b)
JToken val = jo[Encoding.ASCII.GetString(new byte[] b )];
return val != null ? val.ToObject<T>() : default(T);
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
throw new NotImplementedException();
然后只需像这样用[JsonConverter]
属性标记您的EntityAttributes
类:
[JsonConverter(typeof(EntityAttributesConverter))]
class EntityAttributes
public string Name get; set;
public int Level get; set;
public float Strength get; set;
然后像往常一样反序列化:
var attributes = JsonConvert.DeserializeObject<EntityAttributes>(json);
这是一个工作演示(在控制台应用程序中):https://dotnetfiddle.net/VPfbdy
【讨论】:
【参考方案3】:如果需要字节,请使用 JsonUtility.FromJson 反序列化 JSON 文件并简单转换为 System.Text.Encoding.UTF8.GetBytes(myString)。
【讨论】:
是的,这不是问题..问题基本上是如何拥有动态字段名称以上是关于将 JSON 包反序列化为具有自定义属性名称的类的主要内容,如果未能解决你的问题,请参考以下文章
ASP Web API:将对象序列化为 JSON 时指定自定义字段名称
将objective-c自定义对象序列化为OSX的JSON?