如何在 System.Text.Json 中使用 JsonConstructor 属性

Posted

技术标签:

【中文标题】如何在 System.Text.Json 中使用 JsonConstructor 属性【英文标题】:How to use JsonConstructor Attribute in System.Text.Json 【发布时间】:2021-12-28 05:41:29 【问题描述】:

我使用的是 .NET 提供的 Json 命名空间,而不是 Newtonsoft 的命名空间。我有一段代码:

            string text;
            text = File.ReadAllText(EntityDirectory + @"\Json\AbilityTemplates.json");
            foreach (AbilityTemplate template in JsonSerializer.Deserialize<List<AbilityTemplate>>(text)) 
                loaderInterface.AddAbilityTemplate(template);
            

当代码运行到 JsonSerializer.Deserialize 时,抛出了一个 execption。

System.Text.Json.JsonException: 'JSON 值无法转换为 System.Collections.Generic.List`1[Enigma.Game.AbilityTemplate]。路径:$ |行号:0 | BytePositionInLine: 1.'

这是我拥有的 Json 文本:


  
    "ID": "StandardShot",
    "Price": "10",
    "Size": "1",
    "Rarity": "Common",
    "AbilityEffectFactory": "StandardShotEffectFactory"
  ,
  
    "ID": "SelfDestructSingleDamage",
    "Price": "0",
    "Size": "0",
    "Rarity": "NotForPlayer",
    "AbilityEffectFactory": "SelfDestructSingleDamageEffectFactory"
  

我用JsonConstructor Attribute写了一个构造函数,但是好像不行:

        public AbilityTemplate(string id, int price, int size, Rarity rarity, AbilityEffectFactory abilityEffectFactory) 
            Id = id;
            Price = price;
            Size = size;
            Rarity = rarity;
            AbilityEffectFactory = abilityEffectFactory;
        

        [JsonConstructor]
        public AbilityTemplate(string id, int price, int size, Rarity rarity, string abilityEffectFactory) : this(id, price, size, rarity, AbilityEffectFactory.Dictionary[abilityEffectFactory])  

Rarity 是一种枚举类型。

—————————编辑—————————

我把括号从改成[],也让json文本中的字段和参数名完全匹配,但是还是不行。 这是我的新 Json 文本:

[
  
    "id": "StandardShot",
    "price": "10",
    "size": "1",
    "rarity": "Common",
    "abilityEffectFactory": "StandardShotEffectFactory"
  ,
  
    "id": "SelfDestructSingleDamage",
    "price": "0",
    "size": "0",
    "rarity": "NotForPlayer",
    "abilityEffectFactory": "SelfDestructSingleDamageEffectFactory"
  
]

System.InvalidOperationException: 'Enigma.Game.AbilityTemplate' 类型的反序列化构造函数中的每个参数都必须绑定到反序列化时的对象属性或字段。每个参数名称必须与对象上的属性或字段匹配。匹配可以不区分大小写。'

【问题讨论】:

将第一对 ' ' 替换为 "[ ]" 表示你有一个 List/Array 我想你已经完成了。只需删除带有JsonConstructor 属性标记的构造函数,就可以开始了。 能否请您edit 分享minimal reproducible example 的问题?请注意 System.Text.Json 默认区分大小写;如果您的属性名称是Id,您可能需要设置JsonSerializerOptions.PropertyNameCaseInsensitive = true,如JsonSerializer.Deserialize fails 所示。您还需要使用JsonStringEnumConverter 将枚举序列化为字符串,请参阅this answer 至ASP.NET MVC Core API Serialize Enums to String。 【参考方案1】:

第一个问题在于您的 JSON 值。您应该使用 [ ] 而不是 在 JSON 文件中开始和结束数组。要检查 JSON 文件的有效性,您可以使用在线工具,例如 https://codebeautify.org/jsonviewer。这个网站非常适合验证和编辑 JSON 文件。

更改 JSON 文件后,您可以非常轻松地对其进行反序列化。首先,您应该创建一个与 JSON 文件具有相同属性的模型。请注意,属性类型应与 JSON 文件中的类型匹配。示例 JSON 文件中的所有键都是字符串。

对于这个示例文件,您应该制作如下模型:

public class weatherForecastModel
    
        public string ID  get; set; 
        public string Price  get; set; 
        public string Size  get; set; 
        public string Rarity  get; set; 
        public string AbilityEffectFactory  get; set; 
    

之后,您可以使用一行代码将 JSON 反序列化为您的模型:

var jsonString = File.ReadAllText(EntityDirectory + @"\Json\AbilityTemplates.json");
var weatherForecast = JsonSerializer.Deserialize<List<weatherForecastModel>>(jsonString);

或者,如果你使用 Newtonsoft,你可以使用:

var res = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);

【讨论】:

但我想使用 JsonConstructor 来摆脱不必要的附加类。 好吧好吧。但我认为我的解决方案更具可读性和简单性。我总是通过关注 KISS 原则,通过简单的解决方案来解决问题 :) en.wikipedia.org/wiki/KISS_principle

以上是关于如何在 System.Text.Json 中使用 JsonConstructor 属性的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 System.Text.Json 忽略错误值

如何使用 JsonConverter 在 System.Text.Json.JsonSerializer.Serialize() 中排除属性被序列化

如何将类字段与 System.Text.Json.JsonSerializer 一起使用?

如何使用 System.Text.Json 序列化 DateTimeOffset 为 Unix 时间戳

如何反序列化作为 System.Text.Json 中的字符串的嵌套 JSON 对象?

如何使用 System.Text.Json 处理可为空的引用类型?