当 Json.NET 调用参数化构造函数时,它会按名称将 JSON 属性与构造函数参数匹配,使用顺序忽略大小写匹配。但是,对于也对应于类型成员的 JSON 属性,它使用哪个名称 - 成员名称,还是 JsonPropertyAttribute.PropertyName 指定的覆盖类型成员名称?
您似乎希望它在 both 上匹配,因为您的参数命名约定不一致:
-
构造函数参数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() 所示。该算法的简化版本如下:
- 从 JSON 文件中读取属性名称。
- 找到最接近匹配的构造函数参数(如果有)。
- 找到最匹配的成员名称(如果有)。
- 如果 JSON 属性与构造函数参数匹配,则反序列化为该类型并传递给构造函数,
- 但如果不是,则反序列化为适当的成员类型,并在构造后设置成员值。
(当 JSON 属性与 both 匹配时,实现变得复杂,并且开发人员希望,例如,添加到成员的 [JsonProperty(Required = Required.Always)] 在构造函数中设置时应该得到尊重。)
因此,构造函数参数 production_countries 将匹配 JSON 中名为 "production_countries" 的值,而构造函数参数 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();
}
其次,由于您似乎使用构造函数将包含接口的集合中的项目反序列化为具体对象,您可以考虑使用基于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 显示两个选项。