Json.net`JsonConstructor`构造函数参数名称

时间:2017-03-26 18:03:40

标签: c# json.net

通过JsonConstructor使用特定.ctor对IList<ISomeInterface>属性进行反序列化时,参数名称必须与原始 Json名称和JsonProperty映射相匹配不使用属性。

实施例

SpokenLanguages参数始终为null,因为它与spoken_languages不匹配,但有一个JsonProperty映射:

public partial class AClass : ISomeBase
{
    public AClass() { }

    [JsonConstructor]
    public AClass(IList<SysType> SysTypes, IList<ProductionCountry> production_countries, IList<SpokenLanguage> SpokenLanguages)
    {
        this.Genres = SysTypes?.ToList<IGenre>();
        this.ProductionCountries = production_countries?.ToList<IProductionCountry>();
        this.SpokenLanguages = SpokenLanguages?.ToList<ISpokenLanguage>();
    }

    public int Id { get; set; }
    public IList<IGenre> Genres { get; set; }
    [JsonProperty("production_countries")]
    public IList<IProductionCountry> ProductionCountries { get; set; }
    [JsonProperty("spoken_languages")]
    public IList<ISpokenLanguage> SpokenLanguages { get; set; }
}

这只是Json.Net如何调用构造函数的“限制”,还是我缺少的东西。

仅供参考:我是通过Rosyln生成所有这些代码的代码,我不打算为此为每种类型生成JsonConverter ...

1 个答案:

答案 0 :(得分:10)

当Json.NET调用参数化构造函数时,它会按名称将JSON属性与构造函数参数匹配。但是,对于也与类型成员对应的JSON属性,它使用哪个名称 - 成员名称或JsonPropertyAttribute.PropertyName指定的覆盖类型成员名称?

您似乎希望它与两者匹配,因为您的参数命名约定不一致:

  • 构造函数参数production_countries匹配重写的属性名称:

    [JsonProperty("production_countries")]
    public IList<IProductionCountry> ProductionCountries { get; set; }
    
  • 构造函数参数IList<SpokenLanguage> SpokenLanguages匹配反射的名称而不是重写的属性名称:

    [JsonProperty("spoken_languages")]
    public IList<ISpokenLanguage> SpokenLanguages { get; set; }
    
  • IList<SysType> SysTypes都不匹配(这是问题中的拼写错误吗?)

然而,重要的是JSON文件本身的属性名称​​ 构造函数参数名称,如JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()所示。该算法的简化版本如下:

  1. 从JSON文件中读取属性名称。
  2. 找到最接近的匹配构造函数参数(如果有)。
  3. 找到最接近的匹配成员名称(如果有)。
  4. 如果JSON属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
  5. 但如果没有,则反序列化为适当的成员类型,并在构造后设置成员值。
  6. (当JSON属性与匹配时,实现变得复杂,并且开发人员期望在构造函数中设置时,应该尊重添加到成员的[JsonProperty(Required = Required.Always)]。)

    因此构造函数参数production_countries将匹配JSON中名为"production_countries"的值,而构造函数参数SpokenLanguages匹配名为{的JSON值{1}}。

    那么,如何成功反序列化您的类型?首先,您可以使用"spoken_languages"标记构造函数参数,以覆盖反序列化期间使用的构造函数名称:

    [JsonProperty(overrideName)]

    其次,由于您似乎使用构造函数将包含接口的集合中的项目反序列化为具体对象,因此您可以考虑使用基于CustomCreationConverter的单个通用转换器作为ItemConverter

    public partial class AClass : ISomeBase
    {
        public AClass() { }
    
        [JsonConstructor]
        public AClass([JsonProperty("Genres")] IList<SysType> SysTypes, IList<ProductionCountry> production_countries, [JsonProperty("spoken_languages")] IList<SpokenLanguage> SpokenLanguages)
        {
            this.Genres = SysTypes == null ? null : SysTypes.Cast<IGenre>().ToList();
            this.ProductionCountries = production_countries == null ? null : production_countries.Cast<IProductionCountry>().ToList();
            this.SpokenLanguages = SpokenLanguages == null ? null : SpokenLanguages.Cast<ISpokenLanguage>().ToList();
        }
    

    Example fiddle显示两个选项。