【问题标题】:Deserializing a JSON package to a class with custom property names将 JSON 包反序列化为具有自定义属性名称的类
【发布时间】: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)在装饰器中从字节转换为字符串,因为只允许 常量表达式

知道我应该如何解决这个问题吗?

【问题讨论】:

  • 为什么你的常量不能简单地是字符串?
  • 常量的服务器内部表示是字节。必须同步服务器常量和客户端常量已经有点麻烦了,在此之上添加一个字节 -> 字符转换并不理想。
  • 为什么服务器常量不能是字符串? / 为什么服务端不能有常量字节和字符串之间的非常量映射?
  • 也许可以,但是改变内部服务器结构,使常量必须匹配客户端内部结构的方法名称真的有意义吗?
  • 好吧,在一方面,你必须这样做..要么服务器必须提供客户端所期望的客户端,要么必须处理服务器提供的任何东西......无论哪种方式,如果一个一边改变了,另一边也必须改变。可能没有办法解决这个问题

标签: c# json unity3d json.net


【解决方案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)。

      【讨论】:

      • 是的,这不是问题..问题基本上是如何拥有动态字段名称
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多