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

Sus*_*ver 6 c# json.net

使用特定的.ctor via JsonConstructor进行反序列化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; }
}
Run Code Online (Sandbox Code Playgroud)

这只是Json.Net调用构造函数的一个"限制",还是我缺少的东西.

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

dbc*_*dbc 12

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

看起来你希望它匹配两个,因为你的论点命名约定不一致:

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

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

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

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

  1. 从JSON文件中读取属性名称.
  2. 找到最接近的匹配构造函数参数(如果有).
  3. 找到最接近的匹配成员名称(如果有).
  4. 如果JSON属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
  5. 但如果没有,则反序列化为适当的成员类型,并在构造后设置成员值.

(当JSON属性与两者兼容时,实现变得复杂,并且开发人员期望[JsonProperty(Required = Required.Always)]在构造函数中设置时应该遵守添加到成员的内容.)

因此构造函数参数production_countries将匹配"production_countries"JSON 中指定的值,而构造函数参数SpokenLanguages将与命名的JSON值匹配"spoken_languages".

那么,如何成功反序列化您的类型?首先,您可以使用构造函数参数[JsonProperty(overrideName)]来覆盖反序列化期间使用的构造函数名称:

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();
    }
Run Code Online (Sandbox Code Playgroud)

其次,既然你似乎可以用构造反序列化包含接口,具体的对象的集合项目,你可以考虑使用基于一个通用的转换器CustomCreationConverterItemConverter:

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

    public int Id { get; set; }

    [JsonProperty(ItemConverterType = typeof(CustomCreationConverter<IGenre, SysType>))]
    public IList<IGenre> Genres { get; set; }

    [JsonProperty("production_countries", ItemConverterType = typeof(CustomCreationConverter<IProductionCountry, ProductionCountry>))]
    public IList<IProductionCountry> ProductionCountries { get; set; }

    [JsonProperty("spoken_languages", ItemConverterType = typeof(CustomCreationConverter<ISpokenLanguage, SpokenLanguage>))]
    public IList<ISpokenLanguage> SpokenLanguages { get; set; }
}

public class CustomCreationConverter<T, TSerialized> : CustomCreationConverter<T> where TSerialized : T, new()
{
    public override T Create(Type objectType)
    {
        return new TSerialized();
    }
}
Run Code Online (Sandbox Code Playgroud)

显示两个选项的示例小提琴.