gpt4 book ai didi

c# - Json.net `JsonConstructor` 构造函数参数名

转载 作者:太空狗 更新时间:2023-10-29 21:08:00 27 4
gpt4 key购买 nike

当通过 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对于每种类型...

最佳答案

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

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

  • 构造函数参数 production_countries匹配覆盖的属性名称:

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

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

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

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

(当一个 JSON 属性匹配两者时,实现变得复杂,并且开发人员希望,例如,在构造函数中设置时应该考虑添加到成员的 [JsonProperty(Required = Required.Always)] 。)

因此构造函数参数 production_countries将匹配名为 "production_countries" 的值在 JSON 中,构造函数参数 SpokenLanguages匹配名为 "spoken_languages" 的 JSON 值.

那么,如何成功反序列化你的类型呢?首先,您可以用 [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();
}

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

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();
}
}

Example fiddle显示两个选项。

关于c# - Json.net `JsonConstructor` 构造函数参数名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43032552/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com